关于promise的执行顺序问题

看到这样一段代码

Promise.resolve().then(() => {
  console.log(0);
  return Promise.resolve(4) // p2
}).then((res) => {
  console.log(res)
})

Promise.resolve().then(() => {
  console.log(1);
}).then(() => {
  console.log(2);
}).then(() => {
  console.log(3);
}).then(() => {
  console.log(5);
}).then(() =>{
  console.log(6);
})
result: 0123456

对此结果非常疑惑,百思不得其解,本来觉得结果应该是0142356

最后经过多方搜索,在知乎山看到这样一个问题关于promise输出顺序的疑问?, 紫云飞大大的回答解决了我的疑惑,但是大大的解答太过抽象,我也是自己摸索好久才万全明白,在此记录一下。

问题的关键在于在promise内部返回一个thenable对象会发生什么?
1、promise的then是一个microtask微任务
2、promise p return一个promise p2的时候,其实是将这个p2的then加入到了微任务队列中,同时将p的resolve和reject传给p2
3、p2中的then全部调用完成之后,会将p的resolve放入微任务队列,resolve完成之后,这个时候p的状态才会变化,继续执行p的then

所以以上代码的执行过程就是:

输出 微任务队列
[0, 1]
0 [1, p2-then]
1 [p2-then, 2]
[2, resolve]
2 [resolve, 3]
[3, 4]
3 [4, 5]
4 [5, 6]
5 [6]
6 []

一下是几个例子,加深一下理解(队列中的元素对应的是元素所在的then)

Example1
new Promise((resolve, reject) => {
  console.log("外部promise");
  resolve();
})
  .then(() => {
    console.log("外部第一个then");
    return new Promise((resolve, reject) => {
      console.log("内部promise");
      resolve();
    })
    .then(() => {
    console.log("内部第一个then");
    })
    .then(() => {
    console.log("内部第二个then");
    });
  })
  .then(() => {
    console.log("外部第二个then");
  });
输出 微任务队列
外部promise [外部第一个then]
外部第一个then []
内部promise [内部第一个then]
内部第一个then [内部第二个then]
内部第二个then [resolve]
[外部第二个then]
外部第二个then []
Example2
new Promise((resolve, reject) => {
  console.log("外部promise");
  resolve();
})
  .then(() => {
    console.log("外部第一个then");
    new Promise((resolve, reject) => {
      console.log("内部promise");
      resolve();
    })
      .then(() => {
        console.log("内部第一个then");
      })
      .then(() => {
        console.log("内部第二个then");
      });
  })
  .then(() => {
    console.log("外部第二个then");
  });
输出 微任务队列
外部promise [外部第一个then]
外部第一个then []
内部promise [内部第一个then]
[内部第一个then, 外部第二个then]
内部第一个then [外部第二个then, 内部第二个then]
外部第二个then [内部第二个then]
内部第二个then []
Example3
new Promise((resolve, reject) => {
  console.log("外部promise");
  resolve();
})
  .then(() => {
    console.log("外部第一个then");
    let p = new Promise((resolve, reject) => {
      console.log("内部promise");
      resolve();
    })
    p.then(() => {
        console.log("内部第一个then");
      })
    p.then(() => {
        console.log("内部第二个then");
      });
  })
  .then(() => {
    console.log("外部第二个then");
  });
输出 微任务队列
外部promise [外部第一个then]
外部第一个then []
内部promise [内部第一个then]
[内部第一个then,内部第二个then]
[内部第一个then, 内部第二个then, 外部第二个then]
内部第一个then [内部第二个then, 外部第二个then]
内部第二个then [外部第二个then]
外部第二个then []
Example4
let p = new Promise((resolve, reject) => {
  console.log("外部promise");
  resolve();
})
p.then(() => {
    console.log("外部第一个then");
    new Promise((resolve, reject) => {
      console.log("内部promise");
      resolve();
    })
      .then(() => {
        console.log("内部第一个then");
      })
      .then(() => {
        console.log("内部第二个then");
      });
  })
p.then(() => {
    console.log("外部第二个then");
  });
输出 微任务队列
外部promise [外部第一个then, 外部第二个then]
外部第一个then 内部promise [外部第二个then, 内部第一个then]
外部第二个then [内部第一个then, 内部第二个then]
内部第一个then [内部第二个then]
内部第二个then []
Example5
new Promise((resolve, reject) => { // p
  console.log('外部promise');
  resolve();
})
  .then(() => {
    console.log('外部第一个then');
    new Promise((resolve, reject) => { // p2
      console.log('内部promise');
      resolve();
    })
      .then(() => {
        console.log('内部第一个then');
        return Promise.resolve(); // p3
      })
      .then(() => {
        console.log('内部第二个then');
      })
  })
  .then(() => {
    console.log('外部第二个then');
  })
  .then(() => {
    console.log('外部第三个then');
  })
输出 微任务队列
外部promise [外部第一个then]
外部第一个then 内部promise [内部第一个then]
[内部第一个then, 外部第二个then]
内部第一个then [ 外部第二个then, p3-then]
外部第二个then [p3-then, 外部第三个then]
[外部第三个then, p2-resolve]
外部第三个then [p2-resolve]
[内部第二个then]
内部第二个then []
Example6
new Promise((resolve, reject) => { // p
  console.log("外部promise");
  resolve();
})
  .then(() => {
    console.log("外部第一个then");
    new Promise((resolve, reject) => { // p2
      console.log("内部promise");
      resolve();
    })
      .then(() => {
        console.log("内部第一个then");
      })
      .then(() => {
        console.log("内部第二个then");
      });
    return new Promise((resolve, reject) => { // p3
      console.log("内部promise2");
      resolve();
    })
      .then(() => {
        console.log("内部第一个then2");
      })
      .then(() => {
        console.log("内部第二个then2");
      });
  })
  .then(() => {
    console.log("外部第二个then");
  });
输出 微任务队列
外部promise [外部第一个then]
外部第一个then 内部promise [内部第一个then]
内部promise2 [内部第一个then, 内部第一个then2]
内部第一个then [内部第一个then2, 内部第二个then]
内部第一个then2 [内部第二个then, 内部第二个then2]
内部第二个then [内部第二个then2]
内部第二个then2 [p-resolve]
[外部第二个then]
外部第二个then []
Example7
new Promise((resolve, reject) => { // p
  console.log("外部promise");
  resolve();
})
.then(() => {
    console.log("外部第一个then");
    new Promise((resolve, reject) => { // p2
        console.log("内部promise");
        resolve();
    })
    .then(() => {
        console.log("内部第一个then");
    })
    .then(() => {
        console.log("内部第二个then");
    });
    return new Promise((resolve, reject) => { // p3
        console.log("内部promise2");
        resolve();
    })
    .then(() => {
        console.log("内部第一个then2");
    })
    .then(() => {
        console.log("内部第二个then2");
    });
})
.then(() => {
    console.log("外部第二个then");
});
输出 微任务队列
外部promise [外部第一个then]
外部第一个then 内部promise [内部第一个then]
内部promise2 [内部第一个then, 内部第一个then2]
内部第一个then [内部第一个then2, 内部第二个then]
内部第一个then2 [内部第二个then, 内部第二个then2]
内部第二个then [内部第二个then2]
内部第二个then2 [p-resolve]
[外部第二个then]
外部第二个then []

2021年8月31日
最近手动写了一遍Promise,可能有点晚。但是明白了为什么promise返回一个promise的时候会需要等一下才能显示,因为Promise的resolvePromise(x, promise, resolve, reject)方法,如果x是一个promise,那么会调用一次then.call(x, y => {resolvePromise(y, promise, resolve, reject)}, reject), then是微服务,所以需要再次进入微服务队列排队,所以会有这样的现象

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容