I was building an Angular application recently which had to request for data from an API. Since I was using the Angular HttpClient, the response for the data request was wrapped in an observable by default.
Whenever a GET request for data was initiated, I wanted an animated ellipses to be displayed, indicating that the data retrieval process was ongoing. If the data was successfully retrieved, or an error occured during the retrieval process, the animated ellipses should exit the screen.
An observable is a data type that continually emits data to a subscriber that is attached to it. A subscriber is a data type that continually listens for data emitted from an observable it is subscribed to. When a subscriber subscribes to an observable, the subscriber is provided with three handlers to respond to the data that the observable emits. These three handlers are:
- The
nexthandler - executed when the observable source emits a new value from its data sequence, - The
errorhandler - executed when an error occurs in the emission of values from the observable's data sequence, and - The
completehandler - executed when there is no more value available to be emitted from the observable sequence
Assuming the getResults method below returns an observable, the next, error and complete handlers are exemplified in its subscribe method as shown in the code snippet below
getResults().subscribe(
results => console.log('Next handler executed with results: ', results),
error => console.error('Error handler executed with error: ', error),
() => console.log(`Complete handler executed. All values have been emitted`),
);
Being a newbie to observables, I placed the method that hid the animated ellipses in the complete method as demonstrated in the snippet below
getResults().subscribe(
results => displayResults(results),
error => notifyOnError(error.message),
() => hideAnimatedEllipses(),
);
and the animated ellipses was hidden (as long as the request returned no errors). Whenever there was an error, the animated ellipses still danced around the user interface alongside the error message displayed.
In order to solve this, the first thing I did was to execute the hideAnimatedEllipses() method in the complete and error handlers. Sure thing! It worked, but then I got to know about the finalize operator, a better way to get the job done.
Learning about the finalize operator not only solved my problem, it also exposed the fault in my understanding of the three subscription handlers.
I got to find out that after the error handler is executed, further calls to the next handler will have no effect, and that after the complete handler is executed, further calls to next handler will have no effect too. That was why the animated ellipses continued to confidently dance on the user interface in the first instance even after the error message was displayed.
finalize: The
finalizeoperator is executed when an observable's source terminates on complete or on error.
I realised that in the execution of the finalize operator function is where the hideAnimatedEllipses() function should properly reside, and so the code was updated to the code snippet shown below
getResults()
.pipe(finalize(() => hideAnimatedEllipses()))
.subscribe(results => displayResults(results), error => notifyOnError(error.message));
In essense
The
nexthandler is executed when the observable source emits a new value from its data sequence,The
errorhandler is executed when an error occurs in the emission of values from the observable's data sequence. After it is executed, further calls tonextwill have no effect, andThe
completehandler is executed when there is no more value available to be emitted from the observable sequence. After it is executed, further calls tonextwill have no effectThe
finalizeoperator is executed when an observable's source terminates on complete or on error.The code in thefinalizeoperator is also executed when a subscriber unsubscribes from an observable, thusfinalizeacts like thefinallymethod of a promise or atry-catch-finallyblock. Before RxJS v5.5, it was denoted asfinally.
You can find more information about the finalize operator in the RxJS docs here
Cheers!😃
Top comments (1)
Great article! I also moved my loading spinner handling into
finalize, but there is a catch. If you have some heavy work going on inside yournext, this means the loading spinner won't be visible during that time. The finalizer gets called first before running any code inside the next, or error. Therefore, if you want the loading spinner to be visible during any data binding or whatever time consuming work you do, better to add separate spinner handing inside next (or inside error for that matter). Cheers!