Promises vs. Observables with AJAX

A question that always comes up when discussing using observables to make AJAX requests is: “Why not promises?” As we learned in Chapter 1, Creating Observables, a promise represents a single value delivered over time where an observable represents multiple values. An AJAX request is a single value—why complicate things?

Promises are simpler in concept, but the real world always complicates things. Pretend you’re developing the mobile platform for a ridesharing app. Users will typically use the app outside, away from solid Wi-Fi. They’re trying to get somewhere, so they have a low tolerance for latency and errors. With that in mind, we’ll use the following code to build the best user experience for updating the user on the status of their ride:

 let​ request$ = interval(5000)
 .pipe(
  mergeMap(() =>
  ajax(​'/carStatus.json'​)
  .pipe(retry(3))
  )
 );
 
 let​ carStatus = request$.subscribe(updateMap, displayError);
 
 // Later, when the car arrives
 carStatus.unsubscribe();

This observable stream starts off using the interval constructor from Chapter 1, Creating Observables, triggering every five seconds. mergeMap is used to handle an inner observable that makes a request to the backend for the latest update on the car’s status. This is a twist on the mergeMap pattern you’ve seen before—mergeMap works as usual, but the inner observable makes an AJAX request instead. Piped through the inner AJAX observable is an operator you haven’t seen before: retry(3). Intuitively, this operator retries the source observable when an error occurs. Mechanically, this means that on an error, it unsubscribes from the source observable (cleaning everything up from the original request) and then resubscribes (triggering the constructor logic, and therefore the AJAX request again). This retry means that in the event of a shaky connection dropping the request, the request will be made up to three times before finally giving up, resulting in a much better user experience. Finally, we subscribe, updating the map every time a request successfully goes through. If all three requests fail, an error is shown to the user—possibly, they’re out of signal range.

Joe asks:
Joe asks:
Can I Use Observables with Promises?

Many APIs prefer the simplicity of promises over the power of observables. Fortunately, RxJS integrates easily with promise-based systems with the constructor fromPromise and operator toPromise. The constructor takes a promise and emits whatever the promise resolves to, completing the observable immediately after. In this example, we take the native fetch API and wrap it in an observable:

 function​ fetchObservable(endpoint) {
 let​ requestP = fetch(endpoint)
  .then(res => res.json());
 return​ fromPromise(requestP);
 }
 
 fetchObservable(​'/user'​)
 .subscribe(console.log);

On the other hand, perhaps you’re working with a library that expects you to pass in a promise. In that case, the operator toPromise will save your bacon. It waits for the observable to complete and then resolves the promise with the collection of all data the observable emitted. This operator is particularly helpful when refactoring an old, promise-based architecture to use observables:

 let​ helloP = ​of​(​'Hello world!'​)
 .toPromise();
 
 helloP.then(console.log);

Sometimes fromPromise isn’t needed at all. Many RxJS constructors and operators that take an observable will also take a promise and do the conversion for you at the library level. The Car Status example can be adapted to use the fetch API, though some of the advantages of RxJS are lost (in this example, easy access to ‘retry‘).

 let​ request$ = interval(5000)
 .pipe(
  mergeMap(() =>
  fetch(​'/carStatus.json'​)
  .then(res => res.json())
  )
 );
 
 let​ carStatus = request$.subscribe(updateMap, displayError);
 
 // Later, when the car arrives
 carStatus.unsubscribe();

While it may be tempting to switch between observables and promises whenever one is more convenient, I recommend that you stick to the same abstraction whenever possible. This will keep your codebase more consistent and reduce surprises down the road.

This example shows that observables can be used for much smarter error handling and for better user experience without sacrificing code simplicity. When we’re at our desks, making requests to a server running on our machine, things rarely go wrong. Out in the field, everything can and will go wrong. An AJAX request is conceptually a single value, but there’s a lot to be gained from treating one as a potential source of failure (and therefore multiple values). Observables let us gracefully retry when things go wrong. In the next section, you’ll learn how to deal with failure when retrying isn’t an option.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.162.49