Chapter 6. Asynchronous Data Services with Angular 2

Connecting to data services and APIs and handling asynchronous information is a common task in our everyday life as developers. In this sense, Angular 2 provides an unparalleled tool set to help its enthusiastic developers when it comes to consuming, digesting, and transforming all kinds of data fetched from data services.

There are so many possibilities that it would require an entire book to describe all that you can do to connect to APIs or consume information from the filesystem asynchronously through HTTP. In this book, we will only scratch the surface, but the insights covered in this chapter about the HTTP API and its companion classes and tools will give you all that you need to connect your applications to HTTP services in no time, leaving to your creativity all that you can do with them.

In this chapter, we will:

  • Look at the different strategies for handling asynchronous data
  • Introduce Observables and Observers
  • Discuss functional reactive programming and RxJS
  • Review the HTTP class and its API, as part of the
  • Cover the HTTP_PROVIDERS module
  • See all of the preceding points in action through actual code examples

Strategies for handling asynchronous information

Consuming information from an API is a common operation in our daily practice. We consume information over HTTP all the time—when authenticating users by sending out credentials to an authentication service, or when fetching the latest tweets in our favorite Twitter widget. Modern mobile devices have introduced an unparalleled way of consuming remote services, deferring the requests and response consumption until mobile connectivity is available. Responsivity and availability have become big deals. And although modern Internet connections are ultra-fast, there is always a response time involved when serving such information that forces us to put in place mechanisms to handle state in our applications in a transparent way for the end user.

This is not specific to scenarios where we need to consume information from an external resource. Sometimes, we might need to build functionalities that depend on time as a parameter of something, and we need to introduce code patterns that handle this deferred change in the application state.

For all these scenarios, we have always used code patterns, such as the callback pattern, where the function that triggers the asynchronous action expects another function in its signature, which will emit a sort of notification as soon as the asynchronous operation is completed:

function notifyCompletion() {
  console.log('Our asynchronous operation has been completed');
}

function asynchronousOperation(callback) {
  setTimeout(callback, 5000);
}

asynchronousOperation(notifyCompletion);

The problem with this pattern is that code can become quite confusing and cumbersome as the application grows and more and more nested callbacks are introduced. In order to avoid this scenario, Promises introduced a new way of envisioning asynchronous data management by conforming to a neater and more solid interface, in which different asynchronous operations can be chained at the same level and even be split and returned from other functions:

function notifyCompletion() {
  console.log('Our asynchronous operation has been completed');
}

function asynchronousOperation() {
  var promise = new Promise((resolve, reject) => {
    setTimeout(resolve, 5000);    
  });
  return promise;
}

asynchronousOperation().then(notifyCompletion);

The preceding code example is perhaps a bit more verbose, but it definitely produces a more expressive and elegant interface for our asynchronousOperation function.

So, Promises took over the coding arena by storm and no developer out there seems to question the great value they bring to the game. So why do we need another paradigm? Well, because sometimes we might need to produce a response output that follows a more complex digest process as it is being returned, or even cancel the whole process. This cannot be done with Promises, because they are triggered as soon as they're instanced. In other words, Promises are not lazy. On the other hand, the possibility of tearing down an asynchronous operation after it has been fired but not completed yet can become quite handy in certain scenarios. Promises only allow us to resolve or reject an asynchronous operation, but sometimes we might want to abort everything before getting to that point. On top of that, promises behave as a one-time operation. Once they are resolved, we cannot expect to receive any further information or state change notification unless we rerun everything from scratch. Moreover, we sometimes need a more proactive implementation of async data handling. This is where Observables come into the game.

Observables in a nutshell

An Observable is basically an async event emitter that informs another element, called the Observer, the state has changed. In order to do so, the Observable implements all of the machinery that it needs to produce and emit such async events, and it can be fired and canceled at any time regardless of whether it has emitted the expected data events already or not.

This pattern allows concurrent operations and more advanced logic, since the Observers that subscribe to the Observable async events will react to reflect the state change of the Observable they subscribe to.

These subscribers, which are the Observers we mentioned earlier, will keep listening to whatever happens in the Observable until the Observable is disposed, if that ever happens eventually. In the meantime, information will be updated throughout the application with no intervention whatsoever of triggering routines.

We can probably see all this with more transparency in an actual example. Let's refactor the example we covered when assessing promise-based async operations and replace the setTimeout command with setInterval:

function notifyCompletion() {
  console.log('Our asynchronous operation has been completed');
}

function asynchronousOperation() {
  var promise = new Promise((resolve, reject) => {
    setInterval(resolve, 2000);    
  });
  return promise;
}

asynchronousOperation().then(notifyCompletion);

Copy and paste the preceding snippet in your browser's console window and see what happens: the text Our asynchronous operation has been completed will show up at the dev tools' console only once after 2 seconds and will never be rendered again. The promise resolved itself and the entire async event was terminated at that very moment.

Now, point your browser to an online JavaScript code playground such as JSBIN (https://jsbin.com/), and create a new code snippet enabling just the JavaScript and the Console tabs. Then, make sure you add the RxJS library from the Add library option dropdown (we will need this library to create observables, but don't panic; we will cover this later in the chapter) and insert the following code snippet:

var observable = Rx.Observable.create(observer => {
  setInterval(() => {
    observer.onNext('My async operation');
  }, 2000);
});

observable.subscribe(response => console.log(response));
Observables in a nutshell

Run it and expect some message to appear on the right pane. 2 seconds later, we will see the same message showing up, and then again and again. In this simple example, we created an observable and then subscribed to its changes, throwing to the console whatever it emits (a simple message in this example) as a sort of push notification.

The Observable returns a stream of events and our subscribers receive prompt notification of those streamed events, acting accordingly. This is what the magic of Observables relies on—Observables do not perform an async operation and die (although we can configure them to do so), but start a stream of continuous events we can subscribe our subscribers to.

If we comment out the last line, nothing will happen. The Console pane will remain silent and all the magic will begin only when we subscribe our source object.

That's not all, however. This stream can be the subject of many operations before hitting the Observers subscribed to them. Just as we can grab a collection object, such as an array, and apply functional methods over it such as map() or filter() in order to transform and play around with the array items, we can do the same with the stream of events that are emitted by our Observables. This is what is known as reactive functional programming, and Angular 2 makes the most of this paradigm to handle asynchronous information.

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

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