发现国内很多文章对宏任务和微任务的解释都是有问题的

12 小时 18 分钟前
 moyuman

第一个澄清:任务 vs 宏任务

最近在看面试题,到了这个经典的宏任务和微任务的题目,顺手去 MDN 查了查

发现个很奇怪的问题:MDN 通篇都没有“宏任务”这个词。

深入:微任务与 Javascript 运行时环境 中用的词是“任务 vs 微任务”

于是 Google 了一下“宏任务”这个词,发现中文社区中比较权威的出处应该是这篇 事件循环:微任务和宏任务,这里标注说

“多个任务组成了一个队列,即所谓的“宏任务队列”( v8 术语)”

但我搜索了

都没有找到类似 macrotask 的表述

所以这个“宏任务”的说法是哪来的?用 ai deepresearch 了一下,找到的出处为:

所以“宏任务”的说法,本身只是社区中为了区分与“微任务”产生的。

那么 MDN 中的 “任务” 其实就是我们说的 “宏任务” 了

第二个澄清:同步/异步任务 vs 宏/微任务

很多文章做了类似这样的分类:

JS 代码分两种:同步任务和异步任务,异步任务又分为宏任务和微任务

这其实是把同步/异步任务和宏/微任务,混淆了

MDN 和 Html 规范中关于事件循环的章节,是找不到这种分类的依据的,或者说,根本就没有同步任务和异步任务的概念。

发明“宏任务”这个词是为了区分 task 和 microtask 的话,还可以理解

但把“同步任务”和“异步任务”用在理解事件循环这个概念时,就不太合适了,只会让人越来越乱

事件循环是 JS 能实现同步/异步编程的底层原理,在事件循环这一层只分 task 和 microtask

而“同步”和“异步”则是编程和语言层面的东西,是另一个维度了,完全不该被用在解释“何为事件循环”这件事上

1506 次点击
所在节点    JavaScript
13 条回复
chenliangngng
11 小时 52 分钟前
我学了几年前端,没有看过讲宏任务和微任务的书(比如红宝书),一些经典书,也没有这些。但是面试的时候老是问。后面发现一些自媒体和培训机构和一些杂书(比如忍者秘籍)有讲宏任务和微任务。虽然这个确实是有区别的,我觉得其实就是单独为 promise 开了个任务类型(说是微任务也不对,更像是同步调用了一个延后的任务)。对于 web api ,也就是把更新 dom 的动作放到了适当的位置(也就是所谓的微任务,实际是强行往任务队列中两个任务间插入的,用于操作 dom 的任务)

所以,其实宏任务和微任务,应该是借用的概念,被自媒体和培训机构发扬光大了
charles0
10 小时 45 分钟前
同步/异步和事件循环/微任务是两个层面的概念,前者是如何组织程序结构的,后者是运行时如何实现并发的
cenbiq
8 小时 55 分钟前
确实是,以前我也感觉奇怪,突然前端圈子里就开始漫天说什么宏任务微任务了,一开始只讲事件循环。
coderzhangsan
8 小时 20 分钟前
都是些计算机民科造词,类似的例如"socket 粘包",本质上没理解透彻。
LUO12826
7 小时 53 分钟前
不知道现在还有没有朋友在学或者纠结这些,正好之前略微研究过,用大白话说下我的理解:

首先谈论这个话题,一定要先分清 JS 语言本身和它的宿主环境(浏览器,Node.js 等等)。

在早期,JS 语言本身(注意是它的本身)是完全没有异步的概念的。可以想象 JS 引擎最主要的作用是提供一个叫 runCode 的函数接口,参数是一段 JS 代码,JS 代码跑完后这个接口就返回。但在交互式的 Web 页面里,显然 JS 引擎不可能只跑一趟就完工了,还有按钮 click 、setTimeout 、网络请求返回等事件会在网站加载后某刻发生。这是怎么做到的呢?其实是浏览器,也就是宿主环境来负责的:当你设置一个按钮回调时,浏览器记录下了按钮对应的回调。用户点按钮时,浏览器调用 JS 引擎的 runCode ,把你写的回调传进去执行一下。setTimeout 也是同理,其实是宿主环境帮你在特定时间把回调扔给 JS 引擎跑。

那万一一个按钮回调和一个定时器同时触发咋办?众所周知 JS 选择了单线程作为心智模型,那必然不能让多个 runCode 同时跑,所以要引入一个队列,让这些 js 代码排着队一个个进 runCode ,一个执行完了(也即 runCode 返回了)再跑下一个。这个队列就是任务队列,也就是有些人口中的“宏队列”。在 JS 引擎眼里,它其实不知道什么是异步,也不知道有任务队列,只知道宿主时不时丢点 js 代码让它跑。

到了 ES6 时代,Promise 进入了 JS 官方规范,JS 语言本身的世界里也出现了异步的概念。Promise 产生的异步任务,按照 JS 世界的惯例,也需要排着队一个个执行。而由于这是 JS 语言本身的设计,JS 引擎责无旁贷,也需要增加一个任务队列,这就是“微队列”。这时候,JS 引擎就不只是把 runCode 传进来的代码执行完就行了,它还得看看这段代码执行后,微队列里是不是有活。如果有,那就得把活干完,再让 runCode 返回。

在八股文中,这一般表述为“宏任务中产生的微任务总是紧跟在这个宏任务之后、下个宏任务之前执行”。

故事基本上就是这样,一些细节由于工程实现的方便或者其它人为规定,可能会有出入。
timeblind
4 小时 22 分钟前
"宏任务(macrotask)"感觉是作为教学工具出现的,mdn 和 nodejs 的 doc 里都没有出现过,不是标准术语。在 Promise 被引入之前只有 task 这个概念,引入后多了"微任务(microtask)"。 但是 microtask 和 task 不太对称,大家就把以前的 task 叫做 macrotask 用于区分。 [JS 代码分两种:同步任务和异步任务,异步任务又分为宏任务和微任务] 这样的话完全把 js 历史掩盖过去,本末倒置了。 我的理解是"宏任务"是异步的基本单位(甚至可以把同步代码看作一个宏任务),“微任务”是实现插队的优先级机制
datou
4 小时 10 分钟前
简中没有任何值得参考的 IT 相关内容
b2504420230
3 小时 53 分钟前
很久没能见到这么纯粹的技术讨论了。现在感觉都没人味了。
chaominruan
3 小时 21 分钟前
过去把消息队列简单分为宏队列和微队列,这种说法目前已无法满足复杂的浏览器环境,取而代之的是一种更加灵活多变的处理方式。可以看看这篇文章: https://www.ruanchaomin.com/blog/posts/225
koor
2 小时 35 分钟前
浏览器早就没有宏任务微任务的说法了,现在叫队列模型,微任务队列、交互队列之类的
FrankFang128
1 小时 41 分钟前
你搜一下强缓存和弱缓存,你会发现只在简中里提到过这两个概念。
Ericcccccccc
1 小时 37 分钟前
@b2504420230 因为这些问题现在和 ai 聊很快就能获得相当准确的答案。公司原来有个讨论 golang 的群 ai 能力上来之后都没人聊天了。
Al0rid4l
1 小时 34 分钟前
HTML 规范中确实是叫 Task, 不过 macrotask 这个词老外也用, 至少在十多年前就这么用了, 这里 https://stackoverflow.com/questions/25915634/difference-between-microtask-and-macrotask-within-an-event-loop-context 提到了 Promise A+ 规范中有提过 macro-task 这个词. 不过最早哪来的这个词也没考古到

但是比起这两个词, 更有问题的其实是事件循环这个词, 虽然 HTML 规范有定义, 但这只是给浏览器的, 而 Nodejs 的事件循环和浏览器的事件循环其实完全不是一个东西, 这东西并不跟 JS 绑定 (你也可以造一个没有事件循环的 JS runtime

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1226093

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX