宏任务与微任务
宏任务(macro-task)
定义
消息队列中的任务称为宏任务。
产生
宿主环境提供的方法是宏任务,例如setTimeout, setInterval。这些都是浏览器或者Node环境实现的。
执行
不断从消息队列中取出并被事件循环执行。
类型
注意⚠️:
- ✅代表是宏任务
|
浏览器 |
Node |
I/O |
✅ |
✅ |
setTimeout |
✅ |
✅ |
setInterval |
✅ |
✅ |
requestAnimationFrame |
✅ |
❌ |
setImmediate |
❌ |
✅ |
- ⚠️:有些地方会列出来UI Rendering,说这个也是宏任务,但根据HTML规范文档,发现这很显然是和微任务平行的一个操作步骤
- requestAnimationFrame姑且也算是宏任务吧,requestAnimationFrame在MDN的定义为,下次页面重绘前所执行的操作,而重绘也是作为宏任务的一个步骤来存在的,且该步骤晚于微任务的执行。
- setImmediate:用于中断长时间运行的操作并在浏览器完成其他操作(例如事件和显示更新)后立即运行回调函数。
- UI render:一轮事件循环执行结束之后,下轮事件循环执行之前开始进行UI render
微任务
产生原因
在前面我们知道其实浏览器的消息循环系统是由消息队列和事件循环配合实现的,但是后来为何又出现了微任务呢?因为消息队列中这种粗时间颗粒度的任务已经不能胜任部分领域的需求,所以又出现了一种新的技术——微任务。微任务可以在实时性和效率之间做一个有效的权衡。通常我们把消息队列中的任务称为宏任务,每个宏任务中都包含了一个微任务队列。
产生
由js引擎自身提供的是微任务,例如Promise。基本上平时接触到的除了Promise都是宏任务
执行
每个宏任务都有一个微任务队列,在宏任务结束前会执行微任务里面的任务。
在当前宏任务中的 JavaScript 快执行完成时,也就在 JavaScript 引擎准备退出全局执行上下文并清空调用栈的时候,JavaScript 引擎会检查全局执行上下文中的微任务队列,然后按照顺序执行队列中的微任务。WHATWG 把执行微任务的时间点称为检查点。
如果在执行微任务的过程中,产生了新的微任务,同样会将该微任务添加到微任务队列中,V8 引擎一直循环执行微任务队列中的任务,直到队列为空才算执行结束。也就是说在执行微任务过程中产生的新的微任务并不会推迟到下个宏任务中执行,而是在当前的宏任务中继续执行。
类别
|
浏览器 |
Node |
Promise.then catch finally |
✅ |
✅ |
MutationObserver |
✅ |
❌ |
process.nextTick |
❌ |
✅ |
MutationObserver: 提供了监视对DOM树所做更改的能力,创建并返回一个新的 MutationObserver 它会在指定的DOM发生变化时被调用。
process.nextTick:定义出一个动作,并且让这个动作在下一个事件轮询的时间点上执行
宏任务微任务执行图
参考:
浏览器工作原理与实践