最近一段时间再复习Event loop的时候,遇到promise,以及混合着async/await!!!简直是要了我的小命。正当我一筹莫展之际,有幸读到一篇掘金社区上此类问题的文章:Eventloop不可怕,可怕的是遇上Promise顿时觉得醍醐灌顶。故与诸君分享。
Easy Mode:
来试一下这个开胃菜。
setTimeout(()=>{
console.log(1)
},0)
Promise.resolve().then(()=>{
console.log(2)
})
console.log(3)
体会:简单考题。考察eventloop的执行顺序以及宏任务和微任务。输出结果是:[3,2,1]
Normal Mode
第一题是不是不难?那第二题也不难呀!
setTimeout(()=>{
console.log(1)
},0)
let a=new Promise((resolve)=>{
console.log(2)
resolve()
}).then(()=>{
console.log(3)
}).then(()=>{
console.log(4)
})
console.log(5)
体会:考察eventloop和promise.then的执行方式。先上结果:[2,5,3,4,1]。由一点需要注意的是:Promise的链式调用then,每次都会在内部生成一个新的Promise,然后执行then,在执行的过程中不断向微任务(microtask)推入新的函数,因此直至微任务(microtask)的队列清空后才会执行下一波的macrotask。
Hard Mode
I promise。。。。这道题一点都不难
round 1
new Promise((resolve,reject)=>{
console.log("promise1")
resolve()
}).then(()=>{
console.log("then11")
new Promise((resolve,reject)=>{
console.log("promise2")
resolve()
}).then(()=>{
console.log("then21")
}).then(()=>{
console.log("then23")
})
}).then(()=>{
console.log("then12")
})
这个是在第二个例子上的改进。主要体现在再promise.then中又创建了一个promise。MMP 还能不能愉快的玩耍了?你在这玩俄罗斯套娃呢?
吐槽归吐槽,言归正传,遇到这种嵌套的Promise时不要慌(废话,我现在岂止是慌,我慌的一匹。)。首先心中要有一个队列,能够将这些函数放到相应的队列中去问题就迎刃而解了。
第一轮:
输出:promise1
micro task queue:[promise1的第一个then]
第二轮:
输出:then11,prmoise2
micro task queue:[prmosie2的第一个then,promise1的第二个then]
第三轮:
输出:then21,then12
micro task quque:[promise2的第二个then]
第四轮:
输出:then 23
round 2
那如果说这边的Promise中then返回一个Promise呢??
new Promise((resolve,reject)=>{
console.log("promise1")
resolve()
}).then(()=>{
console.log("then11")
return new Promise((resolve,reject)=>{
console.log("promise2")
resolve()
}).then(()=>{
console.log("then21")
}).then(()=>{
console.log("then23")
})
}).then(()=>{
console.log("then12")
})
我看你就是在为难我胖虎。这个考的重点是promise返回一个promise的时候,then12相当于是挂载了新的promise的最后一个then的返回值上。所以结果是:[promise1,then11,promise2,then21,then23,then12]
round 3
那要是多来几个promise呢?
new Promise((resolve,reject)=>{
console.log("promise1")
resolve()
}).then(()=>{
console.log("then11")
new Promise((resolve,reject)=>{
console.log("promise2")
resolve()
}).then(()=>{
console.log("then21")
}).then(()=>{
console.log("then23")
})
}).then(()=>{
console.log("then12")
})
new Promise((resolve,reject)=>{
console.log("promise3")
resolve()
}).then(()=>{
console.log("then31")
})
你这是想让我死。哎,有什么办法呢?来吧:
第一轮:
输出:promise1,promise3
micro task queue:[promise1的第一个then,promise3的then]
第二轮:
输出:then11,promise2,then31
micro task queue:[promise2的第一个then,prmosie1的第一个then]
第三轮:
输出:then21,then12
micro task queue:[promise2的第二个then]
第四轮:
输出:then 23
Master Mode
你头伸过来,给你看看async/await这个好东西
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');
考察在async/await之下,对Eventloop的影响。
async/await仅仅影响的是函数内的执行,而不会影响到函数体外的执行顺序。也就是说async1()并不会阻塞后续程序的执行,**await async2()
相当于一个Promise,console.log("async1 end");
相当于前方Promise的then之后执行的函数。**
输出结果:[script start,async1 start,async2,promise1,script end,async1 end,promise2,settimeout]
Hell mode
小伙子,不错嘛,前四轮都挺过来了,一看就是个骨骼精奇的人。来来来,尝尝这大碗宽面。不不不,大杂烩。这是我毕生的功力了!
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");
});
async1()
new Promise(function (resolve) {
console.log("promise1");
resolve();
}).then(function () {
console.log("promise2");
});
setImmediate(()=>{
console.log("setImmediate")
})
process.nextTick(()=>{
console.log("process")
})
console.log('script end');
F**K。你能不能要点脸。你已经不是想让我死了。你是想让我永世不得超生。
第一轮:
输出:[script start,async1 start,async2,promise1,script end]
macro task queue:[setTimeout,setImmediate]
micro task quequ:[process.nextTick,async2的promise.then,Promise.then]
因为nextTick优先级高于promise.then的优先级。
第二轮:
输出:[process,async1 end,promise2]
macro task quequ:[setTimeout,setImmediate]
micro task queue:[];
第三轮:
输出:settimeout
macro task quequ:[setImmediate]
micro task queue:[];
第四轮:
输出:setImmediate