Promise真题详解
解释会涉及到事件循环等知识点,如果这一点薄弱的可以先去了解一下事件循环
第一题
没必要上来就放大招,先来个简单的,这是我之前看文章收藏的一道题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| console.log("start"); setTimeout(() => { console.log("children2") Promise.resolve().then(() => { console.log("children3") }) }, 0)
new Promise(function(resolve, reject) { console.log("children4") setTimeout(function() { console.log("children5") resolve("children6") }, 0) }).then(res => { console.log("children7") setTimeout(() => { console.log(res) }, 0) });
|
- 遇到这种promise题首先想到的就是出题人的需求,promise类型的题都是要执行结果,你只需要一行一行代码的分析就可以
- 先执行同步的代码,比如第一行的
console.log("start")
,所以第一个输出start
- 下一行执行到
setTimeout
,要知道,setTimeout
是同步的,但是里面的回调函数是异步任务,并且要放置到宏任务队列,此时宏任务队列有一个等待执行的函数
- 接着下一行的
new Promise(...)
,由于其传入的函数是立即执行的,所以第二个输出children4
- 下一行又遇到
setTimeout
,执行,里面的实参回调函数为异步任务,放到宏任务队列中,此时宏任务队列有两个等待执行的函数
- 有很多人会去看then,要知道由于
new Promise(...)
的实例对象此时还是执行中状态pending
,then中的第一个回调是不执行的,所以先不考虑then
- 同步的任务执行完毕,先看微任务队列有没有待执行的函数,没有。去宏任务执行。第一个,也就是第一个
setTimeout(...)
,so第三个输出children2
- 下一行的
Promise.resolve()
返回的值是成功状态的promise实例对象,并将它后面的.then(..)
中的函数放到微任务队列待执行
- 第一个宏任务执行完毕就要去微任务队列查看是否有待执行的任务,就是说,每执行完一个宏任务都要去微任务队列看有没有任务,微任务队列清空,宏任务才执行。
- 此时微任务队列有一个任务,所以执行;第四个输出children3,微任务队列为空,去执行宏任务队列
- 接着第五个输出children5,执行了
resolve(...)
,此时外层的new Promise()
改变状态为成功态
- 由于外层
new Promise(..)
实例对象的状态改变,其.then
中的第一个成功函数可以执行,并且接受的值为resolve(..)
传入的实参。当然这个.then
中的函数也是要放到微任务队列中的。
- 执行微任务队列中的任务,第六个输出children7,下一行的
setTimeout(..)
中的函数放到宏任务队列
- 查看微任务队列,空;去执行宏任务中的任务。第七个输出children6;那个res值就是上文
resolve(...)
传入的实参
第一题只是“开胃菜”,当然第一题如果理解的很透彻了,那么后面的题就都是”下酒菜“,这种事件循环类的题最好是画图理解,有两个队列往里面填充任务,这样看起来方面一些
第二题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| 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"); });
|
- 先执行
new Promise(..)
中的同步任务,第一个输出外部promise
- 遇到
resolve()
,说明这个promise实例是成功状态,将其后面的第一个.then()
放到微任务队列,第二个.then()
由于前一个.then()
还是正在执行状态,所以里面的函数暂存
- 执行微任务队列,第二个输出外部第一个then,触发return后面的new Promise,所以第三个输出内部promise,走到
resolve()
,这个promise状态改变,其后面的第一个.then()
放到微任务队列,第二个.then
暂存
- 执行微任务队列,第四个输出内部第一个then,而
then()
中的函数默认return一个新的Promise实例,所以第二个.then()
中的函数放到微任务队列。并且执行第五个输出内部第二个then,同时return一个新的Promise实例对象。
- 这时候最外层的第一个
.then()
有return新的Promise,所以第二个.then()
放到微任务队列。
- 执行微任务队列,所以第六个输出外部第二个then
第三题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| 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"); });
|
这一题其实就是第二题修改版
- 首先执行
new Promise()
内的同步任务,第一个输出外部promise,遇到resolve()
,new Promise变成成功状态,后面的第一个.then()
放到微任务队列,第二个.then()
暂存。
- 执行微任务队列第二个输出外部第一个then,执行new Promise()中的同步任务,所以第三个输出内部promise,遇到resolve()状态改变,后面的第一个
.then()
放到微任务队列,后面的.then()
暂存。
- 此时这个正在执行的
.then()
return的是undefined,所以外面的最后一个.then()
,放到微任务队列。
- 执行微任务队列第一个,所以第四个输出内部第一个then,并且return的也是一个undefined,后面的
.then()
也放到微任务队列
- 接着执行下一个微任务队列中的任务,也就是最外层的
.then()
中的函数,第五个输出外部第二个then
- 最后一个微任务,也就是最内层的
.then()
第六个输出内部第二个then
更多题…..
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| async function async1() { console.log("async1 start") await async2(); console.log("async1 end") };
async function async2() { console.log("async2") };
console.log("script start");
setTimeout(function() { console.log("setTimeout") }, 0);
async1();
new Promise(function(resolve) { console.log("promise1") resolve() }).then(function() { console.log("promise2") });
console.log("script end");
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| console.log("start"); setTimeout(() => { console.log("children2") Promise.resolve().then(() => { console.log("children3") }) }, 0)
new Promise(function(resolve, reject) { console.log("children4") setTimeout(function() { console.log("children5") resolve("children6") }, 0) }).then(res => { console.log("children7") setTimeout(() => { console.log(res) }, 0) });
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| var p = new Promise(resolve => { console.log(4); resolve(5); }).then(resolve => { console.log(resolve); });
function func1() { console.log(1); };
function fun2() { setTimeout(() => { console.log(2); }); func1(); console.log(3);
new Promise(resolve => { resolve(); }).then(resolve => { console.log('新的resolve'); })
p.then(resolve => { console.log(7); }).then(resolve => { console.log(6); }); } fun2()
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| async function async1() { console.log('async1 start'); const result = await async2(); console.log(result); console.log('async1 end'); } async function async2() { console.log('async'); return "testAwait"; } console.log('script start'); setTimeout(function() { console.log('setTimeout'); }, 0); async1(); new Promise(function(resolve) { console.log('promise1'); resolve(); }).then(function() { console.log('promise2'); }); new Promise(function(resolve) { console.log('promise3'); resolve(); }).then(function() { console.log('promise4'); }); console.log('script end');
|