赞
踩
这是一道涉及事件循环的笔试题:
题目:
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'); // script start // async1 start // async2 // promise1 // script end' // async1 end // promise2 // setTimeout
在分析这道题前先说说几个知识点:
(macro)task(又称为宏任务),可以理解是每次执行栈执行的代码就是一个宏任务。
浏览器为了能够使得JS内部(macro)task与DOM任务能够有序的执行,会在一个(macro)task执行结束之后,在下一个(macro)task执行开始前,对页面进行重新渲染:
(macro)task -> 渲染 -> (macro) task ...
(macro)task主要包括:
microtask(又称为微任务),可以理解是在当前task执行结束后立即执行的任务。也就是在当前task任务后,在下一个task之前,在渲染之前。
在某个宏任务执行之后,就会将在它执行期间产生的所有微任务都执行完毕。
microtask主要包括:
在事件循环中,每进行一次循环操作称为 tick,每一次 tick 的任务处理模型是比较复杂的,但关键步骤如下:
流程图如下:
Promise中的异步体现在then和catch中,所以写在Promise中的代码是被当做同步任务立即执行的。
在async/await中,在出现await之前,其中的代码也是立即执行,在出现await时发生了什么?
await是一个让出线程的标志。await后面紧跟着的表达式会先执行,将接着await下面的代码加到micromask中,然后就会跳出整个 async函数执行后面的代码。
由于因为async await 本身就是promise+generator的语法糖。所以await后面的代码是microtask。所以对于本题中的:
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
等价于:
async function async1() {
console.log('async1 start');
Promise.reselve(async2().then(() => {
console.log('async1 end');
}))
}
了解上面的知识点后,对于本题就很简单了:
首先进入第一个宏任务(script整体代码),遇到同步任务直接执行,即输出 ‘script start’
遇到setTimeout将其放到宏任务队列
遇到async1(),将async1函数里面的同步任务直接执行,输出‘async1 start’,然后将await紧跟着的表达式执行,执行async2(),输出‘async2’,最后将await后面的代码加入到微任务队列,跳出函数async1,执行下面的代码
遇到Promise,将里面的同步任务立即执行,输出‘promise1’,将then后面的代码加入到微任务队列.
最后立即执行console.log(‘script end’),输出‘script end’。
到此,第一个宏任务结束,紧接着执行这一轮的微任务,依次执行微任务队列,输出‘async1 end’,再输出‘promise2’
微任务执行完毕,接着执行下一个宏任务,这里只有setTimeout,执行它,输出‘setTimeout’
结束流程
async function async1() { console.log('async1 start'); await async2(); console.log('async1 end'); } async function async2() { //async2做出如下更改: new Promise(function(resolve) { console.log('promise1'); resolve(); }).then(function() { console.log('promise2'); }); } console.log('script start'); setTimeout(function() { console.log('setTimeout'); }, 0) async1(); new Promise(function(resolve) { console.log('promise3'); resolve(); }).then(function() { console.log('promise4'); }); console.log('script end'); // script start // async1 start // promise1 // promise3 // script end // promise2 // async1 end // promise4 // setTimeout
async function async1() { console.log('async1 start'); await async2(); //更改如下: setTimeout(function() { console.log(' setTimeout1') // 第三个宏任务 },0) } async function async2() { //更改如下: setTimeout(function() { console.log('setTimeout2') },0) // 第二个宏任务 } console.log('script start'); setTimeout(function() { console.log('setTimeout3'); }, 0) // 第一个宏任务 async1(); new Promise(function(resolve) { console.log('promise1'); resolve(); }).then(function() { console.log('promise2'); }); console.log('script end'); // script start // async1 start // promise1 // script end // promise2 // setTimeout3 // setTimeout2 // setTimeout1
async function a1 () { console.log('a1 start'); await a2(); console.log('a1 end');// 第二个微任务 } async function a2 () { console.log('a2'); } console.log('script start'); setTimeout(() => { console.log('setTimeout') }, 0) // 第一个宏任务 Promise.resolve().then(() => { console.log('promise1'); }) // 第一个微任务 a1(); let promise2 = new Promise((resolve) => { resolve('promise2.then') console.log('promise2') }) promise2.then((res) => { console.log(res)// 第三个微任务 Promise.resolve().then(() => { console.log('promise3')//第4个微任务 }) }) console.log('script end') // script start // a1 start // a2 // promise2 // script end // promise1 // a1 end // promise2.then // promise3 // setTimeout
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。