当前位置: 首页 > 知识库问答 >
问题:

事件循环上下文中微任务和宏任务的区别

戎兴言
2023-03-14

我刚刚读完Promises/A规范,偶然发现了术语microtask和macrotask:参见http://promisesaplus.com/#notes

我以前从未听说过这些术语,现在我很好奇会有什么区别?

我已经试图在网上找到一些信息,但我找到的只是w3.org档案馆的这篇文章(这篇文章没有向我解释其中的区别):http://lists.w3.org/Archives/Public/public-nextweb/2013Jul/0018.html

此外,我还发现了一个名为“macrotask”的npm模块:https://www.npmjs.org/package/macrotask同样,还没有明确到底是什么区别。

我所知道的是,它与事件循环有关,如 https://html.spec.whatwg.org/multipage/webappapis.html#task-queue 和 https://html.spec.whatwg.org/multipage/webappapis.html#perform-a-microtask-checkpoint 中所述

我知道,根据WHATWG规范,理论上我应该能够自己提取差异。但是我相信其他人也可以从专家给出的简短解释中受益。

共有5个答案

梁修贤
2023-03-14
热门标签
颛孙高义
2023-03-14
相关问题
孔乐邦
2023-03-14

我认为我们不能讨论与堆栈分离的事件循环,所以:

JS有三个“堆栈”:

  • 所有同步调用的标准堆栈(一个函数调用另一个函数等)
  • 用于具有较高优先级的所有异步操作(process.nextTick、Promises、Object.observe、MutationObserver)的微任务队列(或作业队列或微任务堆栈)
  • 所有优先级较低的异步操作(setTimeout、setInterval、setImmediate、requestAnimationFrame、I/O、UI渲染)的宏任务队列(或事件队列、任务队列、宏任务队列)
|=======|
| macro |
| [...] |
|       |
|=======|
| micro |
| [...] |
|       |
|=======|
| stack |
| [...] |
|       |
|=======|

事件循环的工作方式如下:

  • 从堆栈自下而上执行所有内容,只有当堆栈为空时,检查上面的队列中发生了什么
  • 检查微堆栈并在堆栈的帮助下执行那里的所有内容(如果需要),一个接一个的微任务,直到微任务队列为空或不需要任何执行,然后只检查宏堆栈
  • 检查宏堆栈并在堆栈的帮助下执行那里的所有内容(如果需要)

如果堆栈不为空,则不会触及微堆栈。如果微堆栈不为空或者不需要任何执行,宏堆栈将不会被触及。

总结一下:微任务队列几乎与宏任务队列相同,但这些任务(process.nextTick,Promises,Object.observe,MutationObserver)的优先级高于宏任务。

微类似于宏,但优先级更高。

这里有理解一切的“终极”代码。



       
  
console.log('stack [1]');
setTimeout(() => console.log("macro [2]"), 0);
setTimeout(() => console.log("macro [3]"), 1);

const p = Promise.resolve();
for(let i = 0; i < 3; i++) p.then(() => {
    setTimeout(() => {
        console.log('stack [4]')
        setTimeout(() => console.log("macro [5]"), 0);
        p.then(() => console.log('micro [6]'));
    }, 0);
    console.log("stack [7]");
});

console.log("macro [8]");

丁鹏鹍
2023-03-14
  • 一个事件循环有一个或多个任务队列。(任务队列是宏任务队列)
  • 每个事件循环都有一个微任务队列。
  • 任务队列=宏任务队列!=微任务队列
  • 可以将任务推送到宏任务队列或微任务队列
  • 当任务被推送到队列(微/宏)中时,我们表示准备工作完成,因此现在可以执行任务了。

当调用堆栈为空时,执行以下步骤-

  • 在任务队列中选择最早的任务(任务 A)
  • 如果任务 A 为 null(表示任务队列为空),请跳至步骤 6
  • 将“当前正在运行的任务”设置为“任务 A”
  • 运行
  • “任务A”(表示运行回调函数
  • 将“当前正在运行的任务”设置为空,删除“任务A”
  • 执行微任务队列
    • a).在微任务队列中选择最早的任务(任务X)
    • (b).如果任务 x 为空(表示微任务队列为空),请跳至步骤 (g)
    • (c).将“当前正在运行的任务”设置为“任务 X”
    • (d).运行“任务X”
    • (e).将“当前正在运行的任务”设置为空,删除“任务X”
    • f).在微任务队列中选择下一个最旧的任务,跳转到步骤(b)
    • (g).完成微任务队列;
      < li >运行宏任务队列中最旧的任务,然后将其删除。 < li >运行微任务队列中所有可用的任务,然后删除它们。 < li >下一轮:运行宏任务队列中的下一个任务(跳转步骤2)
      < li >当任务(在宏任务队列中)正在运行时,可能会注册新的事件。因此可能会产生新的任务。下面是两个新创建的任务: < ul > < li>promiseA.then()的回调是一个任务 < ul > < li >promise被解决/拒绝:

牟焱
2023-03-14

事件循环的一次循环将正好有一个来自宏任务队列的任务被处理(在WHATWG规范中,这个队列被简单地称为任务队列)。在该宏任务完成后,所有可用的微任务将被处理,即在相同的循环周期内。当这些微任务被处理时,它们可以排队更多的微任务,这些微任务将被一个接一个地运行,直到微任务队列被用尽。

如果一个微任务递归地将其他微任务排队,则可能需要很长时间才能处理下一个宏任务。这意味着,您可能会导致UI被阻止,或者应用程序中的一些完成I/O空闲。

但是,至少关于 Node.js 的 process.nextTick 函数(将微任务排队),通过 process.maxTickDepth 有一个内置的保护来防止这种阻塞。此值设置为默认值 1000,在达到此限制后减少对微任务的进一步处理,从而允许处理下一个宏任务)

基本上,当您需要以同步方式异步执行任务时(即,当您希望在最短的将来执行此(微)任务时),可以使用微任务。否则,请坚持执行宏任务。

宏任务:setTimeout、setInterval、setImmediate、requestAnimationFrame、I/O、UI渲染
微任务:进程。nextTick,Promises,queueMicrotask,突变观察者

 类似资料:
  • 问题内容: 我刚读完Promises / A+规范,偶然发现了术语microtask和macrotask: 我以前从未听说过这些术语,现在我很好奇可能会有什么不同? 鉴于此WHATWG规范,我知道理论上我应该能够自己提取差异。但是我确信,专家的简短解释也可以使其他人受益。 问题答案: 事件循环的 一种解决 方法是从 宏任务队列中 恰好 处理 一个 任务在WHATWG规范中,该队列简称为 任务队列

  • 浏览器中 JavaScript 的执行流程和 Node.js 中的流程都是基于 事件循环 的。 理解事件循环的工作方式对于代码优化很重要,有时对于正确的架构也很重要。 在本章中,我们首先介绍事件循环工作方式的理论细节,然后介绍该知识的实际应用。 事件循环 事件循环 的概念非常简单。它是一个在 JavaScript 引擎等待任务,执行任务和进入休眠状态等待更多任务这几个状态之间转换的无限循环。 引擎

  • 本文向大家介绍微任务和宏任务有什么区别?相关面试题,主要包含被问及微任务和宏任务有什么区别?时的应答技巧和注意事项,需要的朋友参考一下 宏任务:script整体代码、setTimeout、setInterval... 微任务:Promise.then、Object.observe、process.nextTick... 运行机制:当前宏任务执行结束 -> 是否有微任务 --> 执行当前微任务 --

  • 之所以想到这个问题,是因为在看一篇介绍事件循环的文章的一个例子 执行结果是 关于事件循环、宏任务、微任务我已经比较了解。但是这些内容和事件冒泡、捕获的传递结合起来,之前没有考虑过。 文章开头介绍宏任务包括“UI交互事件”,所以点击事件是宏任务 但从执行结果来看,事件冒泡是属于微任务。当然,一个是事件的点击,一个是事件的传递,性质不同。不知道官方标准是怎么定义这部分内容的?另外,和这个有关的标准,是

  • 我正在设计一个应用程序,它有一个经常性的任务,即只要应用程序处于前台,就可以将状态发送到一个专用服务器。 在我的网上搜索中,我看到了几种不同的方法,我想知道什么是最好的方法。 安排服务器调用的最佳方法是什么? 我看到的选项是: > 定时器。 ScheduledThreadPoolExecutor. 服务。 带有AlarmManager的BroadcastReciever。 你的意见呢? 编辑: 我

  • Promise 的处理程序(handlers).then、.catch 和 .finally 都是异步的。 即便一个 promise 立即被 resolve,.then、.catch 和 .finally 下面 的代码也会在这些处理程序(handler)之前被执行。 示例代码如下: let promise = Promise.resolve(); promise.then(() => alert