JavaScript中的宏任务与微任务

这个概念其实挺抽象的,要理解它,得从JavaScript运行机制开始聊起。

众所周知,JavaScript是单线程的,也就是说,同一时间只能做一件事,如果有某个耗费时间很长的任务,它就会造成线程卡死,反映到宏观上就可能会造成页面卡顿,无响应,甚至崩溃等。所以JavaScript引入了很多异步编程的概念。

要理清楚宏任务和微任务,必须得先搞明白JavaScript的运行机制才可以。

异步编程是为了解决某些任务需要等待而产生的,比如加载页面时还需要用ajax/axios调用后端接口,有可能接口会因为网络原因返回较慢,但如果要让页面等着接口返回后再加载,那必然是体验很不好的。所以聪明的程序员通常会把页面加载作为同步任务,而调用接口时使用异步任务。

网上有一张很有名的图:

img

用文字表述来讲,同步任务与异步任务,它们的执行方式定义是这样的:

  • 同步任务和异步任务分别进入不同的执行环境,同步的进入主线程,异步的进入Event Table并注册回调函数。
  • 当指定的异步任务完成时,Event Table会将这个函数移入Event Queue。
  • 主线程内的任务不断执行,执行完毕为空时,会去Event Queue中读取对应的函数,进入主线程执行。
  • 上述过程会不断重复,也就是常说的Event Loop(事件循环)。

每一次循环操作称之为一个tick。同步任务都在主线程上执行,形成一个执行栈,主线程之外,事件触发线程管理着一个任务队列,只要异步任务有了运行结果,就在任务队列之中放置一个事件。一旦执行栈中的所有同步任务执行完毕(此时JS引擎空闲),系统就会读取任务队列,将可运行的异步任务添加到可执行栈中,开始执行。下图解释了一个事件循环是怎么执行的。

img

那么宏任务和微任务和这里有什么联系呢?

宏任务被称作macrotask,在执行栈中每次执行的代码段就是一个宏任务,也包括每次从Event Queue中获取一个事件回调并放在执行栈中执行。

浏览器为了能够使得JS内部宏任务与DOM任务能够有序的执行,会在一个宏任务执行结束后,在下一个宏任务执行开始前,对页面进行重新渲染。

都有哪些宏任务:

1
2
3
4
5
6
7
8
script(整体代码)
setTimeout
setInterval
I/O
UI交互事件
postMessage
MessageChannel
setImmediate(Node.js 环境)

微任务被称作microtask,i和a一字母之差。微任务是在当前宏任务执行结束后立即执行的一系列任务,也就是在当前宏任务之后,渲染之前,下一个宏任务之前。微任务的响应速度比setTimeout更快(这是个宏任务),且无需等待渲染。

在一个宏任务结束后,JS就会将在宏任务执行期间的所有微任务执行完毕。

微任务有:

1
2
3
4
Promise.then
Object.observe
MutaionObserver
process.nextTick(Node.js 环境)

这里有一张图帮助理解:

img

总结(参考https://www.jianshu.com/p/bfc3e319a96b):

宏任务(macrotask) 微任务(microtask)
谁发起的 宿主(Node、浏览器) JS引擎
具体事件 1. script (可以理解为外层同步代码) 2. setTimeout/setInterval 3. UI rendering/UI事件 4. postMessage,MessageChannel 5. setImmediate,I/O(Node.js) 1. Promise 2. MutaionObserver 3. Object.observe(已废弃;Proxy 对象替代) 4. process.nextTick(Node.js)
谁先运行 后运行 先运行
会触发新一轮Tick吗 不会
打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2018-2023 Shawn Zhou
  • Hexo 框架强力驱动 | 主题 - Ayer
  • 访问人数: | 浏览次数:

感谢打赏~

支付宝
微信