JavaScript Async - Returning Promises |
Written by Ian Elliot | |||
Monday, 15 November 2021 | |||
Page 1 of 2 Promises are still relatively new and this means that there are asynchronous functions that don't make use of them. This leads on to the need to promisify existing and future code. In this extract from my book on JavaScript Async we look at some of the inner workings of the promise. This is an extract from the recently published JavaScript Async: Events Callbacks, Promises & Async/Await. Now Available as a Book:JavaScript AsyncYou can buy it from: Amazon Contents
After learning how to use or consume Promises in the previous chapter the next step is to add support for Promises to asynchronous functions and to work with them to create new Promise features. Included in chapter but not in this extract
The Promise MechanismWhen you create a standard Promise you use its constructor and you pass it a function, the executor, that is immediately executed by the constructor. This is the function where you create the asynchronous task and then call resolve or reject accordingly – usually when the asynchronous task has completed. In other words this is the code that does the work. For example, the delay function example introduced in the previous chapter can be written using JavaScript Promises as: function delay(t) { var p = new Promise( function (resolve, reject) { setTimeout( function () { resolve(); }, t); }); return p; } You can see that it has the same basic structure, the only difference is that now the code calls the private resolve and reject functions that are defined within the constructor. The constructor executes this immediately, passing it the private resolve and reject functions and returns the Promise. Notice that within the function that you pass to the constructor, the calls to resolve and reject result in calling all of the onComplete and onError functions that the consumer of the Promise has set up using the then method of the returned Promise object. Only call resolve or reject when the asynchronous task has completed, and return its value or error code in resolve and reject. Now we are in a position to understand the demonstration Promise introduced in the previous chapter: function delay(t, p) { var promise = new Promise( function (resolve, reject) { setTimeout( function () { var r = Math.random(); if (r > p) { resolve(r); } else { reject(r); } }, t); }); return promise; } You can see that what happens is we create a new Promise object which is returned to the caller almost at once. We also use setTimeout to place a function on the event queue which when its time is up calls either the resolve or the reject function with the specified probability passing the random number back as the resolved value. The Then Parameter ProblemAs delay returns a Promise, it seems obvious that it could be used in a chain (see the previous chapter). However, there is a problem. If you try: getTime(); delay(1000,0) .then(getTime) .then(delay(1000,0)) .then(getTime); where getTime is something like: function getTime() { var time = new Date().getTime(); console.log(time); } which shows a timer count in milliseconds, what you discover is that it appears to work, but if you look carefully the getTime functions report times that are only a few milliseconds apart, rather than 1000ms apart. The reason should be easy to spot. The function being passed to the then function has parameters: .then(delay(1000,0)) and this means the function is evaluated at once and not passed to the then to be activated at a later time. The problem is that you cannot pass a parameter to a function that you use in a then. Notice that when it is called by the Promise, the function may be passed any number of parameters depending on the way the Promise is settled. There are a number of solutions to the problem, but none are 100% satisfactory. The first, and most obvious, is not to use a parameter at all, but this would result in a delay function that gave a fixed time delay and this generally isn't what you want. |
|||
Last Updated ( Monday, 15 November 2021 ) |