Promises to the Rescue

Newer asynchronous functions in JavaScript are designed to return a promise instead of taking a callback. A promise is an object through which a function may propagate an error or result sometime in the future. At any time, a promise is in one of three states: pending, resolved, or rejected.

images/promisestates.png

If an asynchronous function has not completed its task, the promise it returned will be in the pending state. Whenever the asynchronous function completes successfully, it will set the promise into the resolved state. At this time, the promise generates or emits the result passed through it—we refer to this as the promise resolves. If an asynchronous function finishes with an error, then it sets the promise into the rejected state. At this time, the promise generates or emits the error passed through it—we refer to this as the promise rejects.

A promise may be created in one of these three states; however, resolved and rejected are end states. Once a promise ends in either of these states, it will never change to another state. Also, a promise may be in the pending state for an unknown period of time or forever—that is, as long as the asynchronous function that returned the promise has not completed its task.

Let’s discuss how promises solve the issues that make callbacks undesirable.

We often pass the result of one synchronous function as an argument to another synchronous function. When working with asynchronous functions, likewise, we often want to pass the result of one function to another. If the asynchronous functions use callbacks, it is extremely hard to achieve this—code becomes clumsy and unwieldy. At the same time, passing results from one function to another is very easy if the asynchronous functions use promises. That’s because promises may form a chain and, as a result, compose really well to pass data from one function to another.

images/promisechain.png

Upon receiving a promise from an asynchronous function, we can either discard that promise or propagate another promise for further handling. Thus, code can form a chain where each function in the chain performs one cohesive operation and leaves it to the next function in the chain to either complete the operation or extend the task for further processing.

Extending the chain of promises is natural and effortless. For this, a function in the chain, as we’ll see, may return a promise or simply return a primitive, an object, or throw an exception—JavaScript will quietly wrap these into a promise to extend the chain.

Promises consistently and clearly discern data from errors by providing two separate channels of communication: the data channel used with then() and the error channel used with catch(). Unlike callbacks, there is no confusion related to parameter ordering or about which is data versus error. Let’s discuss this further with the following illustration.

images/promisechannel.png

Two kinds of functions may be part of a promises chain—the then() functions and the catch() functions. A then() function is used to receive and process data. A catch() function is used to receive and process an error. Depending on what’s returned by each of these functions, the next step in the process is decided.

For example, in the figure the then() functions A and B are followed by an alternating series of then() and catch() function pairs. The then() function A returns a piece of data, and that’s wrapped into a resolving promise. The then() function B receives the resolved data in this promise for processing. This then() function, B, throws an exception, and that’s wrapped into a rejecting promise by JavaScript. Since the result of the then() function, B, is a rejection, the then() function, C, in the chain is skipped and the promise arrives at the following catch() function, D. This catch() function, D, also throws an exception and as a result that exception is passed to the subsequent catch() function, F, skipping the then() function, E. The catch() function, F, returns a piece of data, which is wrapped by JavaScript into a promise, and that arrives into the next then() function, G, in the series. In short, a resolved promise finds the next then() function in the chain while a rejected promise seeks the next catch() function in the chain.

Think of the promises chain as two tracks, top and bottom. When things go well, you stay or move over to the top track. When things blow up or a promise is rejected, you move over or stay on the bottom track.

We discussed the behavior of promises. Let’s dive into code and see how to create and use promises.

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

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