JavaScript 是一门单线程的编程语言,这意味着在 JS 引擎主线程中,同一时间只能执行一个任务,所有任务必须排队依次执行。

单线程的天然缺陷:若前一个任务耗时过长(如大量计算、死循环),会阻塞主线程,导致后续任务无法执行,最终引发程序假死、无响应的问题。为解决阻塞问题,JavaScript 设计了同步任务 + 异步任务的分工方案,结合 Event Loop 实现非阻塞的异步执行。
JavaScript 把所有待执行任务分为两类,由不同机制调度执行,保证主线程不被阻塞:
别称:非耗时任务
执行位置:在主线程执行栈中排队执行
执行规则:前一个任务执行完毕,才能执行后一个任务
典型示例:普通代码逻辑、console.log、变量赋值、同步函数调用
别称:耗时任务
执行方式:委托宿主环境(浏览器 / Node.js)执行,不占用 JS 主线程
回调机制:异步任务完成后,宿主环境会将其回调函数加入任务队列,等待主线程空闲时执行
典型示例:定时器、网络请求、文件 I/O、Promise 回调
Event Loop 是 JavaScript 主线程、宿主环境、任务队列的协作机制,核心执行步骤:
主线程自上而下执行所有同步任务,放入执行栈中依次运行
遇到异步任务,立即委托给宿主环境处理,主线程不等待,继续执行后续同步代码
宿主环境完成异步操作后,将对应的回调函数加入任务队列
主线程执行栈清空(同步任务全部执行完毕),循环读取任务队列中的回调函数,放入执行栈执行
主线程无限重复步骤 4,这个循环执行的机制就是 Event Loop(事件循环)

为了更精细地调度异步任务,提升程序响应性,JavaScript 将异步任务划分为微任务和宏任务两种队列,二者拥有严格的执行优先级。
优先级:高于宏任务
执行时机:当前执行栈清空后,立即执行,会清空所有微任务再进入下一个阶段
常见任务:Promise.then / catch / finally、process.nextTick(Node.js 特有)、MutationObserver(浏览器特有)
优先级:低于微任务
执行时机:等待当前所有同步任务 + 微任务执行完毕后执行
常见任务:setTimeout、setInterval、文件 I/O 操作、网络请求、UI 渲染(浏览器)
同步任务 > 所有微任务 > 宏任务 每一轮事件循环中,必须先清空微任务队列,再执行下一个宏任务。
// 导入 then-fs 模块
import thenFs from "then-fs";
// 同步任务
console.log("A");
// 宏任务(文件 I/O),完成后 .then 注册微任务
thenFs.readFile("./files/1.txt", "utf8").then((data) => {
console.log("B");
});
// 宏任务(定时器),回调加入宏任务队列
setTimeout(() => {
console.log("C");
}, 0);
// 同步任务
console.log("D");执行同步任务:按照代码顺序,依次打印 A 和 D
执行所有微任务:文件读取完成后,Promise.then 微任务执行,打印 B
执行宏任务:微任务队列清空后,执行定时器宏任务,打印 C
A
D
B
CEvent Loop 是 JavaScript 实现非阻塞异步编程的核心机制,解决了单线程的阻塞问题
异步任务分为微任务和宏任务,执行优先级:同步任务 > 微任务 > 宏任务
微任务会在当前任务结束后立即执行,宏任务必须等待所有微任务执行完毕
Promise 系列回调属于微任务,定时器、文件 I/O、网络请求属于宏任务
JavaScript 单线程特性决定了必须依靠 Event Loop 处理异步任务
同步任务优先执行,异步任务由宿主环境托管,完成后进入任务队列
微任务优先级高于宏任务,是理解异步代码执行顺序的关键