Home > Article > Web Front-end > Promises that need to be truly understood
Related learning recommendations: javascript learning tutorial
Promise Regarding API, everyone should be able to use it proficiently, but You may still have knowledge blind spots related to microtasks.
Before starting the text, let us first set the tone in advance for some of the content involved in this article.
In Promise, only callbacks that need to be executed after state changes are involved are considered microtasks, such as then
, catch
, finally
, all other code executions are macro tasks (synchronous execution).
In the above figure, blue indicates synchronous execution and yellow indicates asynchronous execution (thrown into the microtask queue).
We look at this issue according to the ecma specification:
If the Promise status is pending at this time, then the successful or failed callbacks will be added to [ [PromiseFulfillReactions]]
and [[PromiseRejectReactions]]
. If you have looked at the handwritten Promise code, you should be able to find that there are two arrays storing these callback functions.
If the Promise status is non-pending at this time, the callback will become Promise Jobs, which are microtasks.
After understanding the above knowledge, the main film begins.
Promise.resolve() .then(() => { console.log("then1"); Promise.resolve().then(() => { console.log("then1-1"); }); }) .then(() => { console.log("then2"); });复制代码
Everyone should be able to get the correct answer from the above code: then1 → then1 -1 → then2
.
Although then
is executed synchronously, and the status has also changed. But this does not mean that every time we encounter then
, we need to throw its callback into the microtask queue. Instead, we wait for the callback of then
to complete and then execute the corresponding callback according to the situation. operate.
Based on this, we can draw the first conclusion: In the chain call, only after the previous then
callback is executed, the following Only the callbacks in then
will be added to the microtask queue.
Everyone knows that after Promise resolve
, the callback in then
will immediately enter the microtask queue.
So what do you think the output of the following code will be?
let p = Promise.resolve(); p.then(() => { console.log("then1"); Promise.resolve().then(() => { console.log("then1-1"); }); }).then(() => { console.log("then1-2"); }); p.then(() => { console.log("then2"); }); 复制代码
According to our initial understanding, it is not difficult to conclude that then2
will be output after then1-1
, but the actual situation is the opposite.
Based on this, we draw the second conclusion: The beginning of each chain call will first enter the microtask queue in sequence.
Next let’s change the way we write it:
let p = Promise.resolve().then(() => { console.log("then1"); Promise.resolve().then(() => { console.log("then1-1"); }); }).then(() => { console.log("then2"); }); p.then(() => { console.log("then3"); });复制代码
The above code actually has a trap, then
will return a new Promise every time, at this time p
is no longer generated by Promise.resolve()
, but by the last then
, so then3
should be in then2
is printed after.
By the way, we can also optimize the conclusion we reached before: The beginning of each chain call of the same Promise will first enter the microtask queue in sequence.
Can you guess when then1-2
will be printed?
Promise.resolve() .then(() => { console.log("then1"); Promise.resolve() .then(() => { console.log("then1-1"); return 1; }) .then(() => { console.log("then1-2"); }); }) .then(() => { console.log("then2"); }) .then(() => { console.log("then3"); }) .then(() => { console.log("then4"); });复制代码
This question is definitely simple. Remember the first conclusion to get the answer. The following is the analysis:
First timeresolve
After the first then
callback enters the microtask queue and is executed, print then1
the second time resolve
After the first internal then
callback enters the microtask queue, at this time all the external first then
callbacks have been executed, and the second external needs to be The then
callback is also inserted into the microtask queue.
Execute the microtask, print then1-1
and then2
, and then add the callbacks in then
respectively Insert the microtask queue
to execute the microtask and print then1-2
and then3
. The following content will not be explained one by one
Next let’s modify return 1
, and the result will be quite different:
Promise.resolve() .then(() => { console.log("then1"); Promise.resolve() .then(() => { console.log("then1-1"); return Promise.resolve(); }) .then(() => { console.log("then1-2"); }); }) .then(() => { console.log("then2"); }) .then(() => { console.log("then3"); }) .then(() => { console.log("then4"); });复制代码
When we return Promise.resolve( )
, guess when then1-2
will be printed?
The answer is the last one printed.
Why is there such a big change in the execution order of microtasks for return
different things in then
? The following is the author's analysis.
PS:then
返回一个新的 Promise,并且会用这个 Promise 去 resolve
返回值,这个概念需要大家先了解一下。
根据规范 2.3.2,如果 resolve
了一个 Promise,需要为其加上一个 then
并 resolve
。
if (x instanceof MyPromise) { if (x.currentState === PENDING) { } else { x.then(resolve, reject); } return; }复制代码
上述代码节选自手写 Promise 实现。
那么根据 A+ 规范来说,如果我们在 then
中返回了 Promise.resolve
的话会多入队一次微任务,但是这个结论还是与实际不符的,因此我们还需要寻找其他权威的文档。
根据规范 25.6.1.3.2,当 Promise resolve
了一个 Promise 时,会产生一个NewPromiseResolveThenableJob,这是属于 Promise Jobs 中的一种,也就是微任务。
This Job uses the supplied thenable and its then method to resolve the given promise. This process must take place as a Job to ensure that the evaluation of the then method occurs after evaluation of any surrounding code has completed.
并且该 Jobs 还会调用一次 then
函数来 resolve Promise
,这也就又生成了一次微任务。
这就是为什么会触发两次微任务的来源。
文章到这里就完结了,大家有什么疑问都可以在评论区提出。
想了解更多编程学习,敬请关注php培训栏目!
The above is the detailed content of Promises that need to be truly understood. For more information, please follow other related articles on the PHP Chinese website!