【JS】因两道Promise执行题让我产生自我怀疑,从零手写Promise加深原理理解 - 听风是风 - 博客园 (cnblogs.com)
Promise.resolve().then(() => {
console.log(0);
return Promise.resolve(4);
}).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);
})
一开始做这题我给出的答案是:0 1 4 2 3 5 6
给出这个答案是因为我对于then参数回调函数返回值与then方法返回值的关系的理解不够透彻。我虽然知道:
对于2,我们要需要更加深入了解如下问题:
res与thenRes是否为同一个对象?
通过以上例子验证,res和thenRes并非同一个对象。
thenRes如何实现与res状态相同,结果值相同?(第一次微任务关键点)
thenRes = new Promise((resolve, reject) => {
res.then(data => resolve(data), reason => reject(reason))
})
通过以上方式就可以创建一个状态和结果值与res相同的新的Promise对象thenRes。
我们知道即使调用then的promise对象是非pending的,promise.then也不会直接调用then的参数回调函数,而是将参数回调函数加入异步微任务队列,等待同步代码执行完后,异步地执行。这意味着4的打印会延迟一次,即最终打印结果为0 1 2 4 3 5 6
但是实际上该段代码的执行结果为
这意味着实际上4的打印还要再延迟一次,即还有一次微任务产生,那么到底是哪里产生的呢?实际上只有两种可能:
验证方式也很简单,只需要将代码中return Promise.resolve(4) 变动一下即可:
Promise.resolve静态方法作用是快速创建一个fulfilled状态的promise对象, 底层实现还是使用的new Promise方式,为了避免Promise.resolve内部存在隐藏逻辑,我们直接new Promise,发现其实没有影响,最终输出结果不变。
当我们直接return 4时,则会减少一次由于Promise对象复制产生的then开启的微任务,理论上应该打印出来是 0 1 2 4 3 5 6,但是时机结果却是 0 1 4 2 3 5 6,即直接减少了两次微任务。
说明 return "Promise对象",会开启两次微任务,一次是Promise对象复制的then调用,一次是隐式的开启的。
至于return "Promise对象"的隐式开启的微任务作用是啥,为啥要多开启一次几乎无意义的微任务,大家可以参考下(6 封私信) promise.then 中 return Promise.resolve 后,发生了什么? - 知乎 (zhihu.com)
中各个大神的解释,反正
最终结论:then方法参数回调函数返回Promise对象是会开启两次微任务:
最终现象是:若then方法的参数回调函数的返回值为Promise对象,则会影响then方法返回值Promise对象的pending状态延迟2个微任务后改变。
另外不仅仅是then参数回调函数的返回值为Promise对象会开启两次微任务,对于excutor执行器的形参resolve,reject函数,如果它们也接受道一个Promise对象为入参,则同样会开启两次微任务,见如下笔试题:
道理是一样的。
另外需要注意的是对于 Promise.resolve静态方法而言:
验证如下
所以总结如下