专栏首页码力全开浅析 JS 事件循环之 Microtask 和 Macrotask

浅析 JS 事件循环之 Microtask 和 Macrotask

简介

我们在上一篇 《浅析 JS 中的EventLoop 事件循环》 中提到一个 Event Queue,其实在事件循环中 queue 一共有两种,还有一种叫 Job Queue

其中

Event Queue 在 HTML 规范中被称为 Task Queue,但是为了区分,一般都叫作 Macrotask Queue Job Queue 是在 ECMAScript 规范中谈及处理 Promise 回调时提到的,但是由于和 V8 中的实现比较相似,所以一般都称为 Microtask Queue

Macrotask

Macrotasks 包含了解析 HTML、生成 DOM、执行主线程 JS 代码和其他事件如 页面加载、输入、网络事件、定时器事件等。从浏览器的角度,Macrotask 代表的是一些离散的独立的工作。

常见应用 setTimeout, setInterval, setImmediate, requestAnimationFrame, I/O, UI rendering

Microtask

Microtasks 则是为了完成一些更新应用程序状态的较小的任务,如处理 Promise 的回调和 DOM 的修改,以便让这些任务在浏览器重新渲染之前执行。Microtask 应该以异步的方式尽快执行,所以它们的开销比 Macrotask 要小,并且可以使我们在 UI 重新渲染之前执行,避免了不必要的 UI 渲染。

常见应用 process.nextTick, Promises, Object.observe, MutationObserver

执行顺序

Event Loop 的实现需要至少一个 Macrotask Queue 和至少一个 Microtask Queue。为了便于理解,我们都简化成一个。 简单来说,Microtask Queue 具有更高的优先级,即执行一个 Macrotask 任务后,就会清空整个 Microtask Queue,此时如果有新的 Microtask 加入也会被执行。

所以我们来看下面的代码:

执行顺序是什么? 我们已经知道 setTimeout 是 Macrotask,Promise 是 Microtask,而这段代码从上到下执行也是一个 Macrotask

步骤:

  1. 开始执行,执行脚本作为一个任务进入 Macrotask Queue,同时进入调用栈执行
  2. Line 1, 输出 script start
  3. Line 3 的 setTimeout 回调进入 Macrotask Queue 等待
  4. Line 7 的回调进入 Microtask Queue 等待
  5. Line 13 输出 script end,此时脚本执行完成(即完成了一个 Macrotask)
  6. 开始执行 Microtask Queue,从中拿出一个放入调用栈执行
  7. 开始执行 Line 7 的回调,该回调输出 promise1,返回 undefined
  8. Line 9 的回调进入 Microtask Queue,由于 Microtask Queue 没有清空,直接执行该回调,输出 promise2,该回调返回 undefined
  9. Microtask Queue 已清空(此时浏览器可以更新渲染UI),开始将 Macrotask Queue 中任务放入调用栈执行
  10. 执行 Line 3 的回调,输出 setTimeout,Macrotask Queue 清空
  11. 程序执行完成

所以打印顺序为:

script start -> script end -> promise1 -> promise2 -> setTimeout

PS. 上面的这段代码执行流程,建议看原文的倒数第二篇参考文章,有动态交互操作可以演练。

总结

  1. Microtask 相比 Macrotask 具有更高的优先级
  2. Macrotask 总是在 JS 代码执行完成并且 Microtask Queue 清空之后执行
  3. JS 代码执行本身也是一个 Macrotask
  4. Microtask Queue 清空后有可能会重新渲染 UI
  5. Promise 属于 Microtask,setTimeout 属于 Macrotask

总体的执行顺序为:

常规代码 -> promises -> events 和 setTimeout 等

参考文章

ECMA262 Job Queues HTML Standard Task Queue HTML系列:macrotask和microtask microtask and macrotask a hands on approach difference-between-microtask-and-macrotask-within-an-event-loop-context

本文分享自微信公众号 - 码力全开(codingonfire),作者:savokiss

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-06-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 写给前端的正则表达式入门

    在 JavaScript 中,使用 // 即可创建一个正则表达式对象,当然也可以使用 new RegExp()

    savokiss
  • 动图学 JavaScript 之:原型继承

    你是否曾思考为什么我们能使用 JS 中的一些内置属性和方法,比如 .length,.split(),.join()?我们并没有显式地声明它们,那么究竟它们从哪里...

    savokiss
  • 动图学 JavaScript 之:事件循环(Event Loop)

    今天该学习 Event Loop 啦,其实之前我写过一篇 Event Loop 的文章:

    savokiss
  • org.hibernate.MappingException: Could not determine type for: String, at table: Elec_Text, for colum

    org.hibernate.MappingException: Could not determine type for: String, at table: ...

    qubianzhong
  • SSH系列:(3)Hibernate

    py3study
  • RabbitMQ教程(二) ——linux下安装rabbitmq

    生活创客
  • DevOps 从理论到实践指南

    如今 DevOps 已经成为一个流行词,很多公司都在说自己在做 DevOps,但是每个人、每家公司理解的 DevOps 又不尽相同,从 DevOps 诞生的第一...

    CORNERSTONE
  • 模拟退火算法

    attack
  • 模拟退火算法

    爬山算法的思想就是一个劲的找最优解,如果接下来的任何状态都比当前状态差,那么就停止

    attack
  • 【一周简报】美团大众点评合并细节曝光:设联席CEO,独立运营

    image.png 智选SDK一周资讯大事记,将会为您呈现过去一周最受欢迎的SDK资讯、投融资、企业活动、人物访谈和创业故事等信息,让您在最短的时间内了解最火爆...

    BestSDK

扫码关注云+社区

领取腾讯云代金券