I am learning Promise, in order to understand it I read a bit about Event loop of JavaScript. This article briefly introduced the working of event loop such as call stack, event table and message queue.
But I don't know how the call stack deal with the line containing 'return', and what happens thereafter. Below is an example that I wrote to hopefully understand how Promise works based on event loop. Also see http://jsbin.com/puqogulani/edit?js,console if you want to give it a go.
var p1 = new Promise(
function(resolve, reject){
resolve(0);
});
p1.then(function(val){
console.log(val);
p1.then(function(){
console.log("1.1.1");
p1.then(function(){
console.log("1.1.2");
p1.then(function(){
console.log("1.1.3");
});
});
});
p1.then(function(){
console.log("1.2");
})
return 30;
//return new Promise(function(resolve, reject){
// resolve(30);
//});
})
.then(function(val){
console.log(val/2);
});
p1.then(function(){
console.log("2.1");
});
console.log("Start");
As can be seen, there are two "return", using each of them will give a different output order. Specifically, when using return 30;
, 1.1.2, 1.1.3
are after 15
, but when using return new Promise(...)
, 1.1.2, 1.1.3
are before 15
. So what exactly happened when the code reached two different 'return'?
Just to review, a promise can be created with the constructor syntax, like this: let promise = new Promise(function(resolve, reject) { // Code to execute }); The constructor function takes a function as an argument. This function is called the executor function .
Promise. all is actually a promise that takes an array of promises as an input (an iterable). Then it gets resolved when all the promises get resolved or any one of them gets rejected.
The then method returns a Promise which allows for method chaining. If the function passed as handler to then returns a Promise , an equivalent Promise will be exposed to the subsequent then in the method chain. The below snippet simulates asynchronous code with the setTimeout function. Promise.
The difference is described in http://promisesaplus.com/ under the promise resolution procedure.
For the first return value:
2.3.3.4 If then is not a function, fulfill promise with x.
For the second:
2.3.2 If x is a promise, adopt its state [3.4]:
2.3.2.2 If/when x is fulfilled, fulfill promise with the same value.
We can see this implemented q.js. This is one possible implementation but seems to explain the delay:
function coerce(promise) {
var deferred = defer();
Q.nextTick(function () {
try {
promise.then(deferred.resolve, deferred.reject, deferred.notify);
} catch (exception) {
deferred.reject(exception);
}
});
return deferred.promise;
}
When returning a promise from the then
function, we have two separate promise objects: the one returned from the function passed to then
, and the one returned from then
. These need to be connected together so that resolving the first, resolves the second. This is done with promise.then(deferred.resolve, ...)
The first delay comes from Q.nextTick
. This executes the function on the next iteration of the event loop. There's some discussion in the commit comments on why it's needed.
Calling promise.then
adds a further delay of one iteration of the event loop. As required in the spec:
2.2.4 onFulfilled or onRejected must not be called until the execution context stack contains only platform code. [3.1].
The execution would go something like:
p1.then with function containing 1.1.1 is called
function containing 1.1.1 is queued
p1.then with function containing 1.2 is called
function containing 1.2 is queued
Promise resolving to 30 is returned
Q.nextTick function is queued
----------
1.1.1 is printed
p1.then with function containing 1.1.2 is called
function containing 1.1.2 is queued
1.2 is printed
Q.nextTick function is executed
promise.then(deferred.resolve, ...) is queued
----------
1.1.2 is printed
p1.then with function containing 1.1.3 is called
function containing 1.1.3 is queued
promise.then(deferred.resolve, ...) is executed
function containing val/2 is queued
----------
1.1.3 is printed
val/2 is printed
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With