赞
踩
例子:下题你可能会认为100ms之后,由于a变成了false,所以while就中止了,实际不是这样,因为JS是单线程的,所以进入while循环之后,没有「时间」(线程)去跑定时器了,所以这个代码跑起来是个死循环!
var
事件循环是JavaScript实现异步的具体解决方案,其中同步代码直接执行;异步函数先放在异步队列中,待同步函数执行完毕后,轮循执行异步队列中的回调函数。
事件循环中,每进行一次循环操作称为tick,每一个tick的任务处理模型关键步骤如下:
(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.comCopyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。