在循环内使用Promise

时间:2018-10-05 11:22:39

标签: javascript promise

我想了解这段代码的工作原理。我已经兑现承诺了一段时间,但我想知道这里发生了什么。

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

为什么要在其他应许继续执行之前完成显示。

预先感谢

1 个答案:

答案 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");

为什么:

  • promise(传递给构造函数的函数)的 executor函数是同步运行的,因此将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中的“微任务”和任务/宏任务的更多信息。