我想了解这段代码的工作原理。我已经兑现承诺了一段时间,但我想知道这里发生了什么。
for(let i=0 ; i< 3 ;i++){
new Promise((resolve,reject)=>{
console.log("i = "+i)
resolve(i)
})
.then(r=>{
console.log("promise 1 of "+r)
return new Promise((res,rej)=>res(r))
})
.then(r=>{
console.log("promise 2 of "+r)
return new Promise((res,rej)=>res(r))
})
}
console.log("finish")
输出为
i = 0
i = 1
i = 2
finish
promise 1 of 0
promise 1 of 1
promise 1 of 2
promise 2 of 0
promise 2 of 1
promise 2 of 2
为什么要在其他应许继续执行之前完成显示。
预先感谢
答案 0 :(得分:3)
为什么要在其他应许继续执行之前完成显示。
因为该代码中没有任何内容告诉console.log
在运行之前等待诺言完成。如果要这样做,请将它们收集到一个数组中,然后使用:
Promise.all(theArray)
.then(() => {
console.log("finish");
});
...告诉它等所有人。
请记住,{strong>始终会自动异步调用then
处理程序。因此,您的代码创建了三个Promise链,然后在末尾输出console.log
,然后将异步回调返回到then
处理程序-因此这些结果将随后显示。
侧面说明:您问题中的代码可以更简单地编写为:
for(let i = 0; i < 3; i++) {
console.log("i = " + i);
Promise.resolve(i)
.then(r => {
console.log("promise 1 of " + r);
return r;
})
.then(r => {
console.log("promise 2 of " + r);
return r;
});
}
console.log("finish");
为什么:
console.log("i = " + i);
行作为executor函数的第一行是没有区别的,或刚好在创建承诺的那一行之上。Promise.resolve
用您提供的值创建一个已解决的承诺。then
始终创建新的承诺。当您从then
处理程序返回非承诺值时,该值就是承诺then
返回的解决方案值。如果您返回承诺,则创建的承诺then
被“奴役”为您返回的承诺(等待其解决或拒绝,然后执行相同的操作)。在评论中,您提出了一个非常聪明的问题:
如果“ then”被异步调用,那么这些承诺的输出顺序可能不会正确吗?
次要点:then
不是异步调用的,它的 handler (传递给它的函数)是异步调用的。
在一般情况下,是的,没错,您无法预测独立承诺的顺序(未相互链接的承诺)。您可以预测将 链在一起的承诺(链中较早的承诺将在较晚的承诺之前进行处理)。在您的代码中,您具有三个独立的链(一个代表i = 0,一个代表i = 1,另一个代表i = 2);每个链都有两个附加的处理程序(“ 1 of”和“ 2 of”)。因此,您知道链“ i = 0”中的“ 1 of”将在同一链中的“ 2 of”之前发生,但是通常情况下,您不知道i = 0
是第一个还是{ {1}}一个或任何一个。
但是,在这种特定情况下,可以预测顺序 (至少在浏览器中以及在Node.js上),因为每个链中的初始承诺都开始了预先解决,意味着对i = 2
处理程序的调用会在您调用then
时立即放入微任务队列¹。微任务队列在每个任务(也称为“宏任务”)的末尾运行。因此,运行您的主代码的任务将按顺序立即将回调排队到每个链的“ 1 of”处理程序中。当该处理程序运行时,它会将一个微任务排队,以调用“ 2 of”处理程序。因此,自从诺言开始解决以来,我们知道我们将获得您所得到的输出。但是在一般情况下,您是对的,您无法预测链之间的。
¹这是网络术语; JS规范将其称为PromiseJobs队列。 this answer中的“微任务”和任务/宏任务的更多信息。