☰
任务的分类
2026/10/21 6:26:10 网站建设 项目流程

8.2 任务分类

事件循环的核心是任务调度,浏览器将异步任务按优先级划分为**宏任务(MacroTask / Task)与微任务(MicroTask / Job)**两大类,分别维护独立的任务队列。两类任务遵循不同的调度规则,微任务具备更高的执行优先级,能够在两次宏任务之间插队执行,以此实现高优先级任务的及时响应,是理解异步代码执行顺序的核心依据。


8.2.1 宏任务与微任务的区分

两类任务的核心差异在于调度层级与执行优先级,分别对应不同的业务场景与时间粒度。

一、核心定位差异
  • 宏任务:浏览器级别的任务,由浏览器的各个独立线程触发,对应完整的、独立的异步工作单元。每一个宏任务都是一次完整的任务调度单元,事件循环每轮只会处理一个宏任务。
  • 微任务:JavaScript 引擎级别的任务,是当前任务执行过程中产生的小型插队任务。微任务不进入独立的任务调度队列,而是在当前宏任务执行结束后、下一个宏任务开始前批量执行。
二、核心维度对比

对比维度

宏任务(MacroTask)

微任务(MicroTask)

调度层级

浏览器层面调度

JS 引擎层面调度

队列特性

一个事件循环可存在多个宏任务队列(定时器队列、事件队列等)

仅有一个全局微任务队列

执行规则

每轮事件循环仅执行一个宏任务

当前宏任务结束后,全部清空微任务队列

执行粒度

粗粒度,独立完整的任务单元

细粒度,小型补充任务

产生方式

浏览器 Web API 触发回调产生

JS 执行过程中主动生成

响应延迟

较高,需要等待轮询调度

极低,当前任务结束立即执行


8.2.2 常见宏任务与微任务清单

一、常见宏任务

所有由浏览器 Web API 触发、具备独立回调的异步任务均属于宏任务:

任务类型

说明

整体script脚本代码

页面加载后,整段同步脚本本身是第一个宏任务,由浏览器主线程调度执行

setTimeout/setInterval

定时器回调,由定时器线程计时结束后推入宏任务队列

DOM事件回调

点击、滚动、键盘输入等用户交互事件,由事件线程触发后推入宏任务队列

网络请求回调

XMLHttpRequest、fetch的响应回调,由网络线程完成后推入宏任务队列

文件 I/O回调

FileReader等本地文件读取完成回调

setImmediate

IE 浏览器专属的立即执行宏任务,优先级高于普通定时器

UI渲染更新

浏览器的重排重绘、页面渲染本身也是宏任务级别的操作

二、常见微任务

所有在 JS 执行上下文内产生、需要插队执行的异步任务均属于微任务:

任务类型

说明

Promise.then() / catch() / finally()

Promise 的状态变更回调,是最典型的微任务

async / await

异步函数的等待回调,底层基于 Promise 实现,本质是微任务

queueMicrotask()

原生手动创建微任务的 API,用于显式插队执行

MutationObserver

DOM 变化监听回调,DOM 批量变化后触发微任务

Object.observe()

已废弃的对象变化监听,属于微任务

三、特殊任务说明
  1. requestAnimationFrame:渲染前回调,在微任务清空后、正式渲染前执行,属于宏任务与渲染之间的特殊阶段,优先级高于普通宏任务。
  2. requestIdleCallback:浏览器空闲时执行的低优先级任务,在所有宏任务、微任务、渲染都完成后,页面空闲时才执行,优先级最低。

8.2.3 微任务优先执行机制

微任务优先是事件循环的核心调度规则:一个宏任务执行完成后,不会立即执行下一个宏任务,而是先清空当前所有的微任务队列,微任务全部执行完毕后,再进入下一轮宏任务调度。

一、完整事件循环执行流程
  1. 从宏任务队列中取出优先级最高的一个任务,压入调用栈开始执行。
  2. 执行过程中遇到微任务,将其加入微任务队列。
  3. 当前宏任务执行完毕,调用栈完全清空。
  4. 清空微任务队列:依次取出所有微任务执行,执行过程中新产生的微任务也继续加入队列,直到整个微任务队列完全清空。
  5. 浏览器执行 UI 渲染更新(可选,根据渲染时机与页面状态决定)。
  6. 回到步骤 1,执行下一个宏任务,开启新一轮循环。

核心特点:微任务具备「插队权」,只要微任务队列不为空,就不会执行下一个宏任务;即使微任务内部再创建微任务,也会在当前轮次全部执行完毕。

二、经典执行顺序示例
console.log('1. 同步代码开始'); // 宏任务:定时器 setTimeout(() => { console.log('2. setTimeout 宏任务'); }, 0); // 微任务:Promise Promise.resolve().then(() => { console.log('3. Promise then 微任务1'); // 微任务中再产生微任务 Promise.resolve().then(() => { console.log('4. Promise then 微任务2'); }); }); console.log('5. 同步代码结束');
执行结果

1.同步代码开始

5.同步代码结束

3. Promise then微任务1

4. Promise then微任务2

2. setTimeout宏任务

执行顺序解析
  1. 执行整体 script 宏任务,先运行所有同步代码,依次输出 1、5。
  2. 同步代码执行过程中,定时器回调加入宏任务队列,Promise then 加入微任务队列。
  3. 当前宏任务(script)执行完毕,开始清空微任务队列。
  4. 执行第一个微任务,输出 3;执行过程中产生新的微任务,加入微任务队列末尾。
  5. 继续清空微任务,执行第二个微任务,输出 4,微任务队列完全清空。
  6. 微任务全部执行完毕,进入下一轮宏任务调度,执行定时器回调,输出 2。
三、核心应用意义
  • 高优先级任务插队:需要立即响应的逻辑可以包装为微任务,确保在当前任务结束后立刻执行,避免等待多个宏任务调度。
  • 避免阻塞渲染:耗时计算拆分为多个微任务分批执行,避免长时间阻塞宏任务导致页面卡顿。
  • 状态同步:利用微任务优先于渲染的特性,在渲染前同步最终

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询