了解宏任务和微任务谁先执行
前言
我在阅读掘金的时候,看到热榜第一的文章,于是就点开看了看:我入职了
在这篇文章中,作者遇到了这道很经典的面试题:讲讲你对事件循环的理解
作者自信的回答:宏任务先执行
面试官回答到,您可以先回去查查资料
我也在思考?
咦不对呀?我记得是执行宏任务队列前先清空微任务呀。难道是我记错了吗。于是我马上来到我的博客翻了翻笔记
Javascript高级 - 续 - 鲸落 (xiaojunnan.cn)
- 在执行任何一个宏任务之前(不是队列,是一个宏任务),都会先查看微任务队列中是否有任务需要执行
- 也就是宏任务执行之前,必须保证微任务队列是空的;
- 如果不为空,那么就优先执行微任务队列中的任务(回调)
但是我当时并没有注意到,就在这个笔记的上方纪录了这样一句话:main script中的代码优先执行(编写的顶层script代码)
于是我继续往下看,看到评论区也是吵的不可开交
于是为了一探究竟,我自己开始查找资料来验证到底是怎么回事
什么是事件循环
事件循环(Event Loop)是单线程的JavaScript在处理异步事件时进行的一种循环过程,具体来讲,对于异步事件它会先加入到事件队列中挂起,等主线程空闲时会去执行事件队列(Event Queue)中的事件。如此反复循环。事件循环的设计使得 JavaScript 可以在单线程下处理异步操作,避免了阻塞的情况,保证了程序的响应性和流畅性。
js为什么是单线程的?
这里我们可以额外的进行一个思考?为什么js是单线程的,或者说为什么js要设计为单线程?
- 简单性:单线程使得 JavaScript 的并发模型相对简单,不需要考虑多线程之间的同步和竞态条件等复杂问题。这使得开发者更容易编写和调试代码。
- 安全性:由于 JavaScript 运行在浏览器环境中,多线程可能导致安全问题,例如数据竞争和死锁。通过限制为单线程,可以避免这些潜在的问题。
- 前端交互:JavaScript 主要用于前端开发,处理用户界面的交互和响应。单线程模型确保了事件的顺序执行,避免了多个事件同时修改页面状态导致的混乱。
宏任务和微任务
在 JavaScript中任务分为同步与异步任务,其中异步任务又分为两种:宏任务(Macro Task)和 微任务(Micro Task)。
常见宏任务:
- script标签中的代码
- setTimeout
- setInterval
- setImmediate(Node.js)
- IO
- UI 渲染
- MessageChannel
常见微任务:
- Promise.then(非 new Promise)
- async
- await
- process.nextTick(Node.js)
- Object.observe
- MutationObserver
- queueMicrotask
补充:
- setTimeout设置0和setImmediate谁先执行:setImmediate优先级更高
宏任务和微任务到底是怎样的执行顺序
事件循环的整体执行规则是:
- 所有代码作为宏任务进入主线程执行栈,开始执行
- 执行过程中,同步代码会立即执行,宏任务进入宏任务队列,微任务进入微任务队列
- 在执行当前宏任务之前,先读取微任务队列,有则执行,没有执行宏任务
- 本轮宏任务执行完成,回到第2步,继续执行,直至宏任务与微任务队列全部清空
- 第一个宏任务由浏览器创建,即 script 标签所包裹/引用的同步代码,可以将 script 标签看做是其它语言中的 main 函数,所以一开始必然是 main 这个宏任务「先执行」。
- 在「当前」宏任务的执行末尾,会检查微任务队列并清空,才会开启下一轮事件循环,也就是执行「下一个」宏任务。
- 宏任务与宏任务之间不相交,而宏任务内涵了微任务,所以宏任务和微任务是包含关系。因此不能说当前宏任务包含了其它宏任务比如 setTimeout,只能说当前宏任务包含了「创建」下一个宏任务的代码。
综上,整个问题的通用说法根本就不是谁先执行的问题,而是一个宏任务要想结束,必然要去检查且清空微任务队列,才能开启下一轮事件循环(执行下一个宏任务),换句话说,一个宏任务即代表一个事件循环。
所以从完整的js代码来说
- 先执行了script标签这个最大的宏任务,然后执行同步代码,执行了微任务。在微任务结束后,算是一次事件循环结束。
- 执行下一个宏任务,清空微任务队列。
- 这样执行下去,才有“宏任务先执行,微任务后执行”的说法
那么面试馆的角度,他的问题根本上就是想要问:setTimeout和Promise.then谁先执行
那么从这个问题上来说,是Promise.then
先执行。因为setTimeout是宏任务,Promise.then是微任务,在执行宏任务之前先清空微任务。
写在最后
这是我的理解,如果有什么不对欢迎各位大佬指正
参考链接: