首页 > 其他分享 >js中【微任务】和【宏任务】长篇解读

js中【微任务】和【宏任务】长篇解读

时间:2024-09-10 20:54:29浏览次数:11  
标签:setTimeout 队列 js 任务 循环 Promise 长篇 执行

在 JavaScript 中,理解微任务(microtasks)宏任务 (macrotasks)是掌握异步编程和事件循环(Event Loop)机制的关键。这两个概念影响了代码的执行顺序,特别是在涉及异步操作(如 setTimeoutPromiseasync/await 等)时。为了深刻理解它们的差异及其在事件循环中的表现,我们将从最基础的概念出发,逐步解释这些任务的执行机制。

1. JavaScript 的单线程与异步模型

首先,JavaScript 是一门单线程语言,意味着它在同一时刻只能执行一个任务。这一特性使得 JavaScript 在执行同步代码时很容易理解:代码按顺序一行一行地执行,直到所有代码执行完毕。然而,现代应用往往需要处理异步任务,例如网络请求、定时器回调、用户输入等。为了解决这一问题,JavaScript 引入了异步机制,通过事件循环(Event Loop)调度和管理异步任务。

2. 事件循环(Event Loop)的基本概念

JavaScript 的事件循环是处理异步操作的核心机制。事件循环的工作流程如下:

  1. 执行同步任务:JavaScript 引擎首先执行所有的同步任务,这些任务会立即进入调用栈(Call Stack)并被逐个执行。
  2. 处理异步任务:当遇到异步任务时(例如 setTimeout、Promise、I/O 操作等),这些任务不会立即执行,而是被放入相应的任务队列中(宏任务队列或微任务队列)。
  3. 检查微任务队列:当所有同步任务执行完毕,调用栈为空时,事件循环会优先检查并执行微任务队列中的所有任务。
  4. 执行宏任务:在微任务队列清空后,事件循环从宏任务队列中取出下一个宏任务并执行。每次执行完一个宏任务后,事件循环会再次检查微任务队列,依此反复进行。

3. 宏任务(Macrotasks)与微任务(Microtasks)

在 JavaScript 中,任务分为宏任务(macrotask)微任务(microtask)。它们的区别主要体现在任务调度和执行顺序上。

宏任务(Macrotasks)

宏任务是事件循环的主任务,包括所有涉及异步操作的主要任务。宏任务由浏览器或 Node.js 环境调度,并在每轮事件循环中处理一个宏任务。常见的宏任务包括:

  • setTimeoutsetInterval
  • I/O 操作(例如网络请求回调)
  • DOM 事件(如 clickkeydown 等事件)
  • postMessage(在多个窗口或 iframe 之间通信)
  • MessageChannel
  • requestAnimationFrame

这些任务通常需要一定的等待时间(即使是 setTimeout(fn, 0)),并会在事件循环的某个阶段被处理。

微任务(Microtasks)

微任务的执行优先级比宏任务高。每当一个宏任务完成后,事件循环会立即执行微任务队列中的所有任务,只有在微任务队列清空后,才会继续执行下一个宏任务。常见的微任务包括:

  • Promise.then()Promise.catch()Promise.finally()
  • MutationObserver(观察 DOM 变化)
  • queueMicrotask()(用于将函数显式添加到微任务队列)

微任务的优势在于它们可以在当前事件循环周期内尽快执行,确保任务能够快速完成,尤其适合异步操作的回调处理。

4. 事件循环中的任务调度机制

同步任务执行流程

事件循环的第一步是执行所有的同步任务,即将同步代码依次压入调用栈(Call Stack),并按照顺序执行。当调用栈为空时,事件循环将开始处理异步任务。此时,事件循环会检查两个任务队列:

  1. 微任务队列(Microtask Queue)
  2. 宏任务队列(Macrotask Queue)
微任务优先原则

当同步任务执行完毕后,事件循环会首先检查微任务队列。如果微任务队列中有任务,事件循环会一次性执行所有的微任务(即清空微任务队列)。只有当微任务队列为空时,事件循环才会执行宏任务队列中的第一个任务。

宏任务执行流程

每次从宏任务队列中取出一个任务执行后,事件循环会再次检查微任务队列。如果微任务队列不为空,则会立即执行所有的微任务。在微任务队列为空后,才会回到宏任务队列继续处理下一个宏任务。

因此,微任务的执行优先级高于宏任务。即使一个宏任务已经准备好执行,微任务队列中的任务仍会先被执行。

5. 例子:理解微任务与宏任务的执行顺序

console.log('start'); // 同步任务

setTimeout(() => {
    console.log('setTimeout'); // 宏任务
}, 0);

Promise.resolve().then(() => {
    console.log('promise1'); // 微任务
}).then(() => {
    console.log('promise2'); // 微任务
});

console.log('end'); // 同步任务

执行顺序解析:

  1. 同步任务:首先执行 console.log('start'),输出 start
  2. 同步任务:继续执行 console.log('end'),输出 end
  3. 微任务队列Promise.resolve() 的回调被放入微任务队列。事件循环执行完同步任务后,开始执行微任务队列中的任务,先输出 promise1,再输出 promise2
  4. 宏任务队列setTimeout() 的回调被放入宏任务队列。所有微任务完成后,事件循环执行宏任务,输出 setTimeout

最终输出顺序为:

start
end
promise1
promise2
setTimeout

6. queueMicrotask()Promise.then() 的区别

queueMicrotask()Promise.then() 都会将任务加入微任务队列,但它们有一些细微的差别:

  • queueMicrotask():这是一个直接将任务添加到微任务队列的函数,适用于需要在当前事件循环周期内尽快执行的任务。
  • Promise.then():当 Promise 被 resolve 时,其 .then() 回调会被添加到微任务队列。

两者的执行时机基本一致,但 queueMicrotask() 提供了显式控制微任务的能力。

queueMicrotask(() => {
    console.log('microtask');
});

setTimeout(() => {
    console.log('timeout');
}, 0);

Promise.resolve().then(() => {
    console.log('promise');
});

输出顺序为:

microtask
promise
timeout

尽管 setTimeout 的延迟是 0,但微任务 microtaskpromise 仍会优先于宏任务 timeout 执行。

7. 在 Node.js 环境中的区别

在浏览器环境中,微任务和宏任务的执行顺序如上所述。然而,在 Node.js 中,事件循环的机制略有不同。Node.js 的事件循环包括多个阶段,每个阶段处理特定类型的任务。

Node.js 中有一个特殊的微任务机制:process.nextTick(),它的优先级甚至高于微任务。process.nextTick() 的回调会在微任务之前执行,因此它可以用于需要更高优先级的任务。

process.nextTick(() => {
    console.log('nextTick');
});

Promise.resolve().then(() => {
    console.log('promise');
});

setTimeout(() => {
    console.log('timeout');
}, 0);

输出顺序为:

nextTick
promise
timeout

process.nextTick() 的回调会在 Promise.then() 回调之前执行。

8. 常见的微任务和宏任务陷阱

1. setTimeout(fn, 0) 并不会立即执行

setTimeout(fn, 0) 并不会在 0 毫秒后立即执行,而是会将回调放入宏任务队列中。由于微任务具有更高优先级,Promise.then()queueMicrotask() 等微任务会先于 setTimeout 执行。

2. 微任务过多可能导致性能问题

由于微任务总是会在每个事件循环周期内被优先执行,因此如果有过多的微任务被不断添加,它们可能会阻塞宏任务的执行,导致浏览器无法响应用户的交互。

总结

  1. 同步任务:优先执行。
  2. 微任务:每当同步任务执行完

毕或宏任务结束后,立即执行所有微任务。
3. 宏任务:微任务执行完后,才会执行下一个宏任务。
4. 微任务优先于宏任务:在每次事件循环中,微任务总是先于宏任务执行。
5. Node.js 中的 process.nextTick():其回调优先级比微任务更高。

标签:setTimeout,队列,js,任务,循环,Promise,长篇,执行
From: https://blog.csdn.net/2301_79858914/article/details/142106021

相关文章

  • jsp餐厅服务人员评价系统o8pf9
    jsp餐厅服务人员评价系统o8pf9本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表项目功能员工,用户,工作签到,请假信息,考勤信息,服务评价,员工考核技术要求:   开发语言:JSP前端使用:HTML5,CSS,JSP动态网......
  • jsp超市管理系统设计与实现5ojjs本系统(程序+源码+数据库+调试部署+开发环境)带论文文档
    jsp超市管理系统设计与实现5ojjs本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表项目功能会员,商品分类,员工信息,热卖商品,订单信息,商品采购开题报告内容JSP超市管理系统设计与实现(5OJJS)开题内容报告一......
  • jsp超市管理系统的设计与实现103v4 本系统(程序+源码+数据库+调试部署+开发环境)
    jsp超市管理系统的设计与实现10本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表项目功能超市公告,商品分类,用户,商品信息,商品入库,用户订单,商品出库,商品盘点技术要求:   开发语言:JSP前端使用:HTML......
  • jsp超市管理系统的设计s6kuk
    jsp超市管理系统的设计s6kuk本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表项目功能员工,商品信息,商品分类,仓库信息,供应商,进货信息,退货信息,销售信息,进货结算,退货结算,销售结算技术要求:   开......
  • HTML/CSS/JS学习笔记 Day4(HTML--C3 表格)
    跟着该视频学习,记录笔记:【黑马程序员pink老师前端入门教程,零基础必看的h5(html5)+css3+移动端前端视频教程】https://www.bilibili.com/video/BV14J4114768?p=12&vd_source=04ee94ad3f2168d7d5252c857a2bf358Day4 内容梳理:目录HTML3.0表格3.1表格标签(1)语法基本标签......
  • jsp超市管理系统06c97 本系统(程序+源码+数据库+调试部署+开发环境)
    jsp超市管理系统06c97本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表项目功能商品分类,员工,库存信息,进货信息,销售信息技术要求:   开发语言:JSP前端使用:HTML5,CSS,JSP动态网页技术后端使用SpringBo......
  • jsp超市产品保质期管理系统fscqq
    jsp超市产品保质期管理系统fscq本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表项目功能用户,产品种类,产品信息,生产厂家,产品入库,产品出库,保质期技术要求:   开发语言:JSP前端使用:HTML5,CSS,JSP动态......
  • win11任务栏颜色怎么全透明?简单四招设置透明任务栏,保姆级教程!
    在日常使用win11时,任务栏是我们与电脑互动的重要窗口。随着越来越多的用户希望将桌面环境打造成一个既美观又个性化的空间,任务栏的外观便成为了许多人关注的重点。很多用户发现,尽管win11系统提供了半透明的任务栏,但还是渴望实现一种更为极致的全透明效果,以营造出更加和谐的视觉......
  • jsp超市Pos收银管理系统1y6h3
    jsp超市Pos收银管理系统1y6h3本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表项目功能员工,供应商信息,商品分类,商品信息,商品入库,商品出库,商品采购,商品退货技术要求:   开发语言:JSP前端使用:HTML......
  • jsp畅行旅游网站的设计与实现690v7
    jsp畅行旅游网站的设计与实现69本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表项目功能用户,景点类型,景点信息开题报告内容一、项目背景与意义随着互联网技术的不断进步,人们的旅游方式发生了深刻变革。......