0

0

JavaScript事件循环中哪些操作会产生微任务

星降

星降

发布时间:2025-08-22 11:36:02

|

762人浏览过

|

来源于php中文网

原创

微任务主要由promise回调、mutationobserver和queuemicrotask产生。1.promise的.then()、.catch()、.finally()会在状态变化后将回调放入微任务队列;2.mutationobserver用于监听dom变化,其回调作为微任务批量处理以优化性能;3.queuemicrotask是es2021新增api,允许开发者显式安排微任务。这些微任务会在当前宏任务执行完毕后立即全部执行,确保异步操作顺序可控并优化ui更新,从而提升代码执行的一致性和性能表现。

JavaScript事件循环中哪些操作会产生微任务

JavaScript事件循环中,会产生微任务的操作主要集中在几个特定场景:Promise的回调函数(包括

.then()
,
.catch()
,
.finally()
),DOM的
MutationObserver
回调,以及通过
queueMicrotask()
API显式安排的任务。这些微任务会在当前宏任务(比如一次脚本执行、一个定时器回调)执行完毕后,但在下一个宏任务开始之前,被一并处理掉。

JavaScript事件循环中哪些操作会产生微任务

要深入理解微任务,我们得先把它放到JavaScript事件循环的大背景里看。我个人觉得,理解这个机制,是掌握JS异步编程的关键一步,否则很多时候你会发现代码执行顺序和你想的不一样,尤其是在处理UI更新或者复杂的异步流时。

简单来说,事件循环就像个永动机,它不停地检查两类任务队列:宏任务队列(Macrotask Queue)和微任务队列(Microtask Queue)。当我们执行一段JS代码时,它本身就是一个宏任务。这段宏任务执行过程中,如果遇到Promise的

.then()
回调,或者DOM发生了变化触发了
MutationObserver
,这些回调并不会立刻执行。它们会被悄悄地扔进一个叫“微任务队列”的地方。

立即学习Java免费学习笔记(深入)”;

JavaScript事件循环中哪些操作会产生微任务

一个宏任务执行完了,事件循环并不会马上跳到下一个宏任务。它会先去看看微任务队列里有没有东西。如果有,它就会把队列里所有的微任务,一个接一个地、不间断地执行完,直到队列清空。这个过程是“原子性”的,意思是微任务队列一旦开始清空,就不会被打断,直到所有微任务都执行完毕,才会进行浏览器渲染(如果是在浏览器环境)或者去取下一个宏任务。

所以,核心逻辑就是:一个宏任务 -> 清空所有微任务 -> 渲染(浏览器特有) -> 下一个宏任务。理解这个顺序,你就能明白为什么

Promise.resolve().then(...)
会比
setTimeout(..., 0)
先执行了。

JavaScript事件循环中哪些操作会产生微任务

Promise回调为什么是微任务,它和异步有什么关系?

Promise回调被设计成微任务,这背后其实有很深层的考量。你想啊,Promise是为了解决回调地狱,让异步代码更易读、更可控。如果它的回调(比如

then
里头的函数)是宏任务,那会发生什么?

举个例子,假设你有一个Promise链,每一个

then
都对应一个宏任务。那么,当你执行完第一个
then
后,事件循环可能就会去处理其他的宏任务,比如一个
setTimeout
,或者甚至进行一次页面渲染,然后才回来执行你的下一个
then
。这会导致什么问题?

  1. 执行顺序不确定性增加: 你的Promise链会被其他宏任务“打断”,导致链式调用的逻辑变得难以预测。
  2. UI更新的抖动: 如果Promise的某个步骤需要更新UI,而它又是宏任务,那么UI可能会在Promise链的中间步骤被多次更新,造成不必要的重绘和性能损耗,甚至出现闪烁。

把Promise回调设计成微任务,就完美地解决了这些问题。当一个Promise状态从pending变为fulfilled或rejected时,其对应的

then
/
catch
/
finally
回调会被立即放入微任务队列。这意味着:

  • 紧密耦合: 这些回调会紧跟着当前正在执行的同步代码和所有其他微任务之后执行,确保了Promise链的连续性和“立即性”,它们不会被其他宏任务插队。
  • UI更新优化: 在一个宏任务内部,所有由它触发的微任务都会在渲染之前执行。这样,即使你的Promise链条很长,所有相关的DOM操作和数据更新都可以在同一次渲染前完成,避免了多次不必要的重绘,提供了更流畅的用户体验。

我个人觉得,这是Promise设计上最精妙的地方之一,它在保证异步性的同时,又通过微任务机制提供了接近同步的执行确定性。

除了Promise,还有哪些常见的操作会产生微任务,它们有什么用?

除了Promise,微任务的家族成员还有几个。最常见的,我觉得是

MutationObserver
和相对较新的
queueMicrotask

玄鲸Timeline
玄鲸Timeline

一个AI驱动的历史时间线生成平台

下载

1. MutationObserver

这玩意儿听名字就知道跟“变动观察”有关,它就是用来监听DOM树变化的。比如说,你想知道页面上某个元素的属性变了没有,或者子节点被添加删除了没有,

MutationObserver
就能派上用场。

它的回调函数,也就是当DOM变化被观察到时执行的那个函数,就是作为微任务被安排的。为什么是微任务?因为DOM变化可能非常频繁,而且很多时候,一个小的DOM操作可能会连锁引发一系列变化。如果

MutationObserver
的回调是宏任务,那每次DOM变动都可能触发一次宏任务,造成大量的上下文切换和不必要的UI重绘。

作为微任务,

MutationObserver
的回调就能在当前宏任务结束时,批量处理所有观察到的DOM变化。这意味着,即使你在一个宏任务里对DOM进行了十几次修改,
MutationObserver
的回调也只会执行一次(或者说,它会收集所有变化,然后一次性通知你),而且是在浏览器渲染之前。这大大提升了性能,避免了UI的抖动和不必要的计算。

2. queueMicrotask()

这个API是ES2021引入的,它的目的非常明确:允许开发者直接、显式地将一个函数安排为微任务。

console.log('同步代码开始');

queueMicrotask(() => {
  console.log('这是一个微任务');
});

Promise.resolve().then(() => {
  console.log('这是另一个微任务 (Promise)');
});

console.log('同步代码结束');

// 实际输出顺序:
// 同步代码开始
// 同步代码结束
// 这是一个微任务
// 这是一个另一个微任务 (Promise)

你可能会问,有了Promise,有了

setTimeout(0)
,为什么还需要
queueMicrotask
?它的价值在于,它提供了一个比
setTimeout(0)
更“即时”的异步执行机制。
setTimeout(0)
实际上是把任务放到了宏任务队列的末尾,它会等待当前所有微任务和可能的渲染完成后才执行。而
queueMicrotask
则保证了你的回调会在当前宏任务结束后,所有其他微任务执行之前或之中(取决于入队顺序)执行。

我个人觉得,

queueMicrotask
在某些高级场景下非常有用,比如当你需要确保某个操作在UI更新前完成,但又不想引入Promise的额外开销时。它给了开发者更细粒度的控制权,让你能更精确地控制异步代码的执行时机。

微任务与宏任务的执行顺序和区别,对实际开发有什么影响?

理解微任务和宏任务的根本区别以及它们的执行顺序,我觉得是深入前端优化的一个必经之路。说白了,它们决定了你的异步代码什么时候真正跑起来。

核心区别:

  • 宏任务 (Macrotasks): 可以理解为一次“完整”的事件循环周期。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
js正则表达式
js正则表达式

php中文网为大家提供各种js正则表达式语法大全以及各种js正则表达式使用的方法,还有更多js正则表达式的相关文章、相关下载、相关课程,供大家免费下载体验。

514

2023.06.20

js获取当前时间
js获取当前时间

JS全称JavaScript,是一种具有函数优先的轻量级,解释型或即时编译型的编程语言;它是一种属于网络的高级脚本语言,主要用于Web,常用来为网页添加各式各样的动态功能。js怎么获取当前时间呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

244

2023.07.28

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

319

2023.08.03

js是什么意思
js是什么意思

JS是JavaScript的缩写,它是一种广泛应用于网页开发的脚本语言。JavaScript是一种解释性的、基于对象和事件驱动的编程语言,通常用于为网页增加交互性和动态性。它可以在网页上实现复杂的功能和效果,如表单验证、页面元素操作、动画效果、数据交互等。

5328

2023.08.17

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

481

2023.09.01

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

212

2023.09.04

Js中concat和push的区别
Js中concat和push的区别

Js中concat和push的区别:1、concat用于将两个或多个数组合并成一个新数组,并返回这个新数组,而push用于向数组的末尾添加一个或多个元素,并返回修改后的数组的新长度;2、concat不会修改原始数组,是创建新的数组,而push会修改原数组,将新元素添加到原数组的末尾等等。本专题为大家提供concat和push相关的文章、下载、课程内容,供大家免费下载体验。

218

2023.09.14

js截取字符串的方法介绍
js截取字符串的方法介绍

JavaScript字符串截取方法,包括substring、slice、substr、charAt和split方法。这些方法可以根据具体需求,灵活地截取字符串的不同部分。在实际开发中,根据具体情况选择合适的方法进行字符串截取,能够提高代码的效率和可读性 。

219

2023.09.21

C++ 设计模式与软件架构
C++ 设计模式与软件架构

本专题深入讲解 C++ 中的常见设计模式与架构优化,包括单例模式、工厂模式、观察者模式、策略模式、命令模式等,结合实际案例展示如何在 C++ 项目中应用这些模式提升代码可维护性与扩展性。通过案例分析,帮助开发者掌握 如何运用设计模式构建高质量的软件架构,提升系统的灵活性与可扩展性。

0

2026.01.30

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
如何进行WebSocket调试
如何进行WebSocket调试

共1课时 | 0.1万人学习

TypeScript全面解读课程
TypeScript全面解读课程

共26课时 | 5.1万人学习

前端工程化(ES6模块化和webpack打包)
前端工程化(ES6模块化和webpack打包)

共24课时 | 5.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号