事件循环,画个圈圈……
浏览器的事件循环机制
浏览器事件循环图(摘自《javascript忍者秘籍第二版》13章):
宏任务微任务
宏任务:从浏览器角度,代表一个离散的,独立的工作单元
比如:创建主文档对象,解析HTML,执行主线(全局)js代码
更改当前URL和各种事件(页面加载,网络事件,定时器等)
微任务:是更小的任务,微任务要尽可能快的,通过异步方式执行
比如:DOM变化(MutationObserver),Promise回调函数
由于因为async await 本身就是promise+generator的语法糖,所以await后面的也是
从面试题理解运行机制
1 |
|
上面的代码执行结果为:2,4,3,1
我们结合上面的事件循环图来理解下输出结果
- 首先执行主线(全局js代码),碰到定时器代码,定时器时间为0表示尽快执行
定时器是宏任务,于是把定时器任务放入宏任务队列
现在宏任务队列中是(主线,定时器) - 接着往下解析,开始执行promise的代码,遇到promise里的2直接输出
- promise中有一个异步方法,是微任务,于是把他放到微任务队列
- 继续往下执行全局代码,输出4
- 跑完上面的流程,js主线(全局)代码执行完成,同时也是第一个宏任务执行完成了
- 按照事件循环图的流程,开始检查微任务队列是否有任务,有的话执行所有微任务,输出3
- 第一轮循环结束,更新UI主线(全局)任务从宏任务中出队
- 开始新的一轮事件循环,执行队首的宏任务即之前的定时器任务输出1
通过上面的例子我们也可以知道,定时器的执行时间机制:
因为js单线程的本质,我们只能控制定时器何时被加入宏任务队列,而无法控制其何时执行
再看一个例子:
1 |
|
上面这个例题可能会有一些地方难理解,主要是async和await
1 | async function async1() { |
等价于:
1 | async function async1() { |