例子:下题你可能会认为100ms之后,由于a变成了false,所以while就中止了,实际不是这样,因为JS是单线程的,所以进入while循环之后,没有「时间」(线程)去跑定时器了,所以这个代码跑起来是个死循环!
var
事件循环是JavaScript实现异步的具体解决方案,其中同步代码直接执行;异步函数先放在异步队列中,待同步函数执行完毕后,轮循执行异步队列中的回调函数。
事件循环中,每进行一次循环操作称为tick,每一个tick的任务处理模型关键步骤如下:
- 执行一个宏任务(栈中没有就从事件队列中获取)
- 执行过程中如果遇到微任务,就将它添加到微任务的队列中
- 宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)
- 当前宏任务执行完毕,开始检查渲染,然后GUI线程接管渲染
- 渲染完毕后,JS线程接续接管,开始下一个宏任务(从事件队列中获取)
(macro)task宏任务:包括script、setTimeout、I/O、UI交互等
micro task微任务:包括Promise.then、Mutation observer、process.nextTick(node.js环境等)。async/await和Promise实现延迟执行,并在每个task结束时执行。
在每一个事件循环之前,microtask队列总是被清空。
代码中出现setTimeout、async/await、Promise等函数正确的执行顺序是怎样的呢?
先看一道经典面试题目:
async
控制台运行结果为:
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
注:上图为Chrome75.0.3770.142执行结果截图,如果浏览器版本为Chrome61.0.3163.100(低于v73)则promise2先于async1 end打印(最新版本的firefox火狐亦是如此)。
分析执行过程流程图:
"执行整体代码"开始后扫到task放入task queue,扫到微任务放入micro task queue。
分析要点主要记住3点:
(1)Promise中的异步体现在then和catch中,故写在Promise中的代码是被当做同步任务立即执行的;
(2)而在async/await中,在出现await之前其代码也是立即执行的。带async关键字的函数仅仅是把return值包装成promise返回,其他并无不同之处;
(3)await是让出线程的标志:await后面的表达式会先执行一遍(await等的是右侧表达式的结果),将await语句之后的代码加入到micro task中,然后就会跳出整个async函数来执行后续代码。
用上例方法来分析另一道例题:
例2:
setTimeout(() => console.log('setTimeout1'), 0);
setTimeout(() => {
console.log('setTimeout2');
Promise.resolve().then(() => {
console.log('promise2');
Promise.resolve().then(() => {
console.log('promise3');
})
console.log(5)
})
setTimeout(() => console.log('setTimeout4'), 0);
}, 0);
setTimeout(() => console.log('setTimeout3'), 0);
Promise.resolve().then(() => {
console.log('promise1');
})
最后,我们再来一道在node中的异步题目吧:
async
(macro)task宏任务:包括script、setTimeout、I/O、UI交互、setImmediate(nodejs环境中)等 micro task微任务:包括Promise.then、Mutation observer、process.nextTick(node.js环境等)。async/await和Promise实现延迟执行,并在每个task结束时执行。在每一个事件循环之前,microtask队列总是被清空。
windows下的node10.16.3运行结果如上图,Mac的node12.6.0运行结果稍有出入:
具体表现在 async1 end和promise3孰先孰后、setImmediate和setTimeout3孰先孰后的差异。
本文参考链接:
8张图让你一步步看清 async/await 和 promise 的执行顺序segmentfault.com 浏览器和NodeJS中不同的Event Loop · Issue #234 · kaola-fed/bloggithub.com