资讯专栏INFORMATION COLUMN

简要总结microtask和macrotask

yexiaobai / 790人阅读

摘要:众所周知和都属于上述异步任务的一种那到底为什么和会有顺序之分这就是我想分析总结的问题所在了和的作用是为了让浏览器能够从内部获取的内容并确保执行栈能够顺序进行。只要执行栈没有其他在执行,在每个结束时,队列就会在回调后处理。

前言

我是在做前端面试题中看到了setTimeout和Promise的比较,然后第一次看到了microtask和macrotask的概念,在阅读了一些文章之后发现没有一个比较全面易懂的文章,所以我尝试做一个梳理性的总结.

这道经典的面试题引起了我的兴趣
console.log("script start");

setTimeout(function() {
  console.log("setTimeout");
}, 0);

Promise.resolve().then(function() {
  console.log("promise1");
}).then(function() {
  console.log("promise2");
});

console.log("script end");
JavaScript的事件循环机制

首先我们先弄清楚setTimeout和Promise的共同点,也就是我第一次的看到那道面试题的疑惑点.

JavaScript 主线程拥有一个 执行栈 以及一个 任务队列,主线程会依次执行代码,当遇到函数时,会先将函数 入栈,函数运行完毕后再将该函数 出栈,直到所有代码执行完毕。

上面的例子的执行栈执行顺序应该是这样的

console.log("script start");
console.log("script end");
Promise.resolve();

而任务队列的执行顺序应该是这样的

Promise.then(function() {
  console.log("promise1");
});
Promise.then(function() {
  console.log("promise2");
});
setTimeout(function() {
  console.log("setTimeout");
}, 0);

而主线程则会在 清空当前执行栈后,按照先入先出的顺序读取任务队列里面的任务。

众所周知setTimeout和Promise.then()都属于上述异步任务的一种,那到底为什么setTimeout和Promise.then()会有顺序之分,这就是我想分析总结的问题所在了.

macrotasks(tasks) 和 microtasks tasks

tasks的作用是为了让浏览器能够从内部获取javascript / dom的内容并确保执行栈能够顺序进行。

tasks的调度是随处可见的,例如解析HTML,获得鼠标点击的事件回调等等,在这个例子中,我们所迷惑的setTimeout也是一个tasks.

microtasks

microtasks通常用于在当前正在执行的脚本之后直接发生的事情,比如对一系列的行为做出反应,或者做出一些异步的任务,而不需要新建一个全新的tasks。

只要执行栈没有其他javascript在执行,在每个tasks结束时,microtasks队列就会在回调后处理。在microtasks期间排队的任何其他microtasks将被添加到这个队列的末尾并进行处理。

microtasks包括mutation observer callbacks,就像上例中的promise callbacks一样。

所以上面的例子执行顺序的实质是

tasks =>start end以及resolve

microtasks =>promise1和promise2

tasks =>setTimeout

具体应用

需要注意的是,在两个tasks之间,浏览器会重新渲染。这也是我们需要了解tasks和microtasks的一个非常重要的原因.

Vue 中如何使用 MutationObserver 做批量处理? - 顾轶灵的回答 - 知乎

根据 HTML Standard,在每个 task 运行完以后,UI 都会重渲染,那么在 microtask 中就完成数据更新,当前 task 结束就可以得到最新的 UI 了。反之如果新建一个 task 来做数据更新,那么渲染就会进行两次。

浏览器兼容问题

在__Microsoft Edge__, Firefox 40__, __iOS Safari 以及 desktop Safari 8.0.8 中setTimeout会先于Promise

该例子来自Jake Archibald-->Tasks, microtasks, queues and schedules,其中有动画来展现tasks和microtasks的具体工作流程,十分推荐阅读
//html
// Let"s get hold of those elements
var outer = document.querySelector(".outer");
var inner = document.querySelector(".inner");

// Let"s listen for attribute changes on the
// outer element
new MutationObserver(function() {
  console.log("mutate");
}).observe(outer, {
  attributes: true
});

// Here"s a click listener…
function onClick() {
  console.log("click");

  setTimeout(function() {
    console.log("timeout");
  }, 0);

  Promise.resolve().then(function() {
    console.log("promise");
  });

  outer.setAttribute("data-random", Math.random());
}

// …which we"ll attach to both elements
inner.addEventListener("click", onClick);
outer.addEventListener("click", onClick);

在这个例子中,不同浏览器的log是不同的,如下所示

Chrome Firefox Safari edge
click click click click
promise mutate mutate click
mutate click click mutate
click mutate mutate timeout
promise timeout promise promise
mutate promise promise timeout
timeout promise timeout promise
timeout timeout timeout

事实上Chrome是正确的,而且由此可发现microtasks并不是在tasks的结束阶段开始执行,而是在tasks中回调结束之后(只要没有正在执行的JavaScript代码)

总结

tasks会顺序执行,浏览器会在执行间隔重新渲染

microtasks会顺序执行,执行时机为

在没有JavaScript代码执行的callback之后

在每一个tasks之后

由于我是前端初学者,对于JavaScript还很不熟悉,对事件循环的进程模型不是很了解,希望这篇文章能够帮助大家.

事件循环机制建议参考文章

阮一峰-->JavaScript 运行机制详解:再谈Event Loop

HTML Living Standard — Last Updated 9 April 2018

tasks建议参考文章

Jake Archibald-->Tasks, microtasks, queues and schedules

理解 JavaScript 中的 macrotask 和 microtask

setImmediate.js --A YuzuJS production

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/107676.html

相关文章

  • 浅析 JS 事件循环之 Microtask Macrotask

    摘要:常见应用则是为了完成一些更新应用程序状态的较小的任务,如处理的回调和的修改,以便让这些任务在浏览器重新渲染之前执行。常见应用执行顺序的实现需要至少一个和至少一个。 简介 我们在上一篇 《浅析 JS 中的EventLoop 事件循环》 中提到一个 Event Queue,其实在事件循环中 queue 一共有两种,还有一种叫 Job Queue 其中 Event Queue 在 HTML...

    sihai 评论0 收藏0
  • 理解javascript中的事件循环(Event Loop)

    摘要:主线程会暂时存储等异步操作,直接向下执行,当某个异步事件触发时,再通知主线程执行相应的回调函数,通过这种机制,避免了单线程中异步操作耗时对后续任务的影响。 背景 在研究js的异步的实现方式的时候,发现了JavaScript 中的 macrotask 和 microtask 的概念。在查阅了一番资料之后,对其中的执行机制有所了解,下面整理出来,希望可以帮助更多人。 先了解一下js的任务执...

    mykurisu 评论0 收藏0
  • 浏览器环境下的microtaksmacrotasks

    摘要:的回调函数正是处于队列之中。将看做会导致性能问题,回调函数可能会因为渲染等相关产生不必要的延后。浏览器是怎么出错的和在两次点击操作之间运行完成了所有的,就比如的回调函数所展示的,但是似乎有不同的排序算法。 带有可视代码执行顺序的原文链接https://jakearchibald.com/201...,此篇文字并非其完整翻译,加入了一部分自己的理解,比如将其中的task替换为macrot...

    econi 评论0 收藏0
  • 浏览器环境下的microtaksmacrotasks

    摘要:的回调函数正是处于队列之中。将看做会导致性能问题,回调函数可能会因为渲染等相关产生不必要的延后。浏览器是怎么出错的和在两次点击操作之间运行完成了所有的,就比如的回调函数所展示的,但是似乎有不同的排序算法。 带有可视代码执行顺序的原文链接https://jakearchibald.com/201...,此篇文字并非其完整翻译,加入了一部分自己的理解,比如将其中的task替换为macrot...

    FreeZinG 评论0 收藏0
  • 带你彻底弄懂Event Loop

    前言 我在学习浏览器和NodeJS的Event Loop时看了大量的文章,那些文章都写的很好,但是往往是每篇文章有那么几个关键的点,很多篇文章凑在一起综合来看,才可以对这些概念有较为深入的理解。 于是,我在看了大量文章之后,想要写这么一篇博客,不采用官方的描述,结合自己的理解以及示例代码,用最通俗的语言表达出来。希望大家可以通过这篇文章,了解到Event Loop到底是一种什么机制,浏览器和Nod...

    hersion 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<