问题
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'?
回答1:
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
来源:https://stackoverflow.com/questions/41788626/understanding-the-execution-order-of-subsequent-then-handlers-of-an-resolved-p