【问题标题】:How to explain the output order of this code snippet?如何解释此代码段的输出顺序?
【发布时间】:2020-11-13 02:01:58
【问题描述】:

    new Promise((resolve,reject) => {
        console.log('outer promise')
        resolve()
    })
    .then(() => {
        console.log('outer 1 then')
        new Promise((resolve,reject) => {
            console.log('in promise')
            resolve()
        })
        .then(() => {
            console.log('in 1 then')
            return Promise.resolve()
        })
        .then(() => {
            console.log('in 2 then')
        })
    })
    .then(() => {
        console.log('outer 2 then')
    })
    .then(() => {
        console.log('outer 3 then')
    })
    .then(() => {
        console.log('outer 4 then')
    })  

这是我的解释:

1.执行new Promise,输出outer promise

2.然后执行第一个外层,它的回调进入微任务队列。然后第二个外层,然后第三个外层和第四个外层然后执行,但是它们的所有回调都没有进入队列,因为每个每个 then 返回的 promise 仍处于挂起状态。

3.然后执行第一个outer的回调,输出outer 1 then。之后new Promise会输出in promise

4.然后执行第一个内部,它的回调进入微任务队列。第二个内部的回调然后不进入队列

5.现在,第一个outer的回调已经全部结束,也就是说第一个outer返回的promise已经解决了。于是,第二个outer的回调就进入了队列

6.执行队列的第一个任务,输出outer 2 then,并回调第三个任务进入队列。接下来,执行第二个内部任务的回调,输出in 2 then

7.然后执行第三个outer的回调,它会输出outer 3 then,并做第四个的回调然后进入队列。

8.最后执行第四个outer的回调,会输出outer 4 then

因此,输出顺序应该是:

outer promise
outer 1 then
in promise
in 1 then
outer 2 then
in 2 then
outer 3 then
outer 4 then

但它实际上输出:

outer promise
outer 1 then
in promise
in 1 then
outer 2 then
outer 3 then
outer 4 then
in 2 then

我很困惑的是为什么in 2 then最后会输出?为什么outer 2 then,outer 3 then,outer 4 then会连续输出?这与我对事件循环的想法不同。我认为结果与语句return Promise.resolve()有关,但我不知道该语句究竟做了什么以及为什么它会影响输出顺序。

【问题讨论】:

  • 首先你必须返回承诺
  • 我知道,每个then 都会返回一个承诺
  • 我说的是你的new Promise 在第一个调用中,如果你不返回它,那将立即解决
  • 但由于 promise 处于已解决状态,因此它也会立即解决
  • 不,不会。对承诺的 then 调用将返回一个新的待处理承诺。如果回调被执行,那只会解决(或拒绝)。 Promise.resolve().then(x => x) //=> Promise { <state>: "pending" }

标签: javascript event-loop


【解决方案1】:

我会把它推到角落未定义的行为中。您不应依赖 JavaScript 引擎的内部结构以特定顺序执行 then 回调。我可以想象两种适合给定代码的场景。

  1. 内部任务应该在外部任务之前运行。在这里,您应该确保返回内部承诺。然后,您可以移动内部 then 调用并将它们添加到外部 Promise 链中。

    new Promise((resolve,reject) => {
      console.log('outer promise');
      resolve();
    })
    .then(() => {
      console.log('outer 1 then');
      return new Promise((resolve,reject) => { // <- added a return statement
        console.log('in promise');
        resolve();
      });
    })
    .then(() => {
      console.log('in 1 then');
      return Promise.resolve();
    })
    .then(() => {
      console.log('in 2 then');
    })
    .then(() => {
      console.log('outer 2 then');
    })
    .then(() => {
      console.log('outer 3 then');
    })
    .then(() => {
      console.log('outer 4 then');
    });
  2. 您想为内部承诺分割一条路径,并且不在乎在此单独路径之前或之后执行进一步的 then 回调。不应假定两条不同路径之间的执行顺序。但是,您可以在路径内控制顺序。在下面的示例中,in 2 then 应始终在in 1 then 之后执行。不应假定in 1 thenouter 2 then 的顺序。

    const splitPoint = new Promise((resolve,reject) => {
      console.log('outer promise');
      resolve();
    })
    .then(() => {
      console.log('outer 1 then');
      return new Promise((resolve,reject) => { // <- added a return statement
        console.log('in promise');
        resolve();
      });
    });
    
    const path1 = splitPoint.then(() => {
      console.log('in 1 then');
      return Promise.resolve();
    })
    .then(() => {
      console.log('in 2 then');
    });
    
    const path2 = splitPoint.then(() => {
      console.log('outer 2 then');
    })
    .then(() => {
      console.log('outer 3 then');
    })
    .then(() => {
      console.log('outer 4 then');
    });
    
    Promise.all([path1, path2]).then(() => {
      console.log('path1 and path2 finished');
    });

【讨论】:

    猜你喜欢
    • 2016-09-28
    • 1970-01-01
    • 1970-01-01
    • 2020-05-14
    • 1970-01-01
    • 2015-07-13
    • 2010-12-18
    • 2021-04-24
    相关资源
    最近更新 更多