JavaScript引擎是单线程的,仅有一个调用栈,同步任务排队执行;异步能力由浏览器/Node.js提供的Web APIs、任务队列和Event Loop实现,async/await本质仍是微任务调度,不引入多线程。

JavaScript 引擎本身确实是单线程的
所谓“单线程”,是指 JavaScript 运行时只有一个调用栈(call stack),同一时刻只能执行一个同步任务。你写的 console.log()、for 循环、函数调用,都得排队进栈、逐个执行。这不是设计缺陷,而是为了简化 DOM 操作的并发模型——避免两个线程同时修改同一个元素导致状态不一致。
异步能力来自运行环境,不是 JS 语言本身
浏览器或 Node.js 提供了额外的机制来“脱手”耗时操作,让 JS 主线程不被卡住。关键组件包括:
-
Web APIs(如setTimeout、fetch、addEventListener):它们在后台线程或系统级模块中执行,完成后把回调放入任务队列 -
Event Loop:持续检查调用栈是否为空;若空,则从任务队列(macrotask queue)或微任务队列(microtask queue)里取一个回调推入调用栈 -
Promise.then()和queueMicrotask()进入微任务队列;setTimeout、setInterval、I/O 回调进宏任务队列
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');
// 输出顺序一定是:1 → 4 → 3 → 2
常见误解:async/await 是多线程?
不是。async 函数只是语法糖,本质仍是基于 Promise 的微任务调度。它不会开新线程,也不会让 JS 引擎并行执行代码。下面这段代码依然全程跑在主线程上:
async function loadData() {
const res = await fetch('/api/data'); // 这里只是暂停函数执行,不阻塞主线程
const data = await res.json(); // 同样,控制权交还给 Event Loop
return data;
}
真正耗时的网络请求由浏览器底层用 C++ 实现的网络模块处理,JS 只负责注册回调和后续解析。
立即学习“Java免费学习笔记(深入)”;
为什么不能靠 Web Workers 绕过单线程限制?
Web Workers 确实能创建新线程,但它和主线程完全隔离:无法访问 document、window 或任何 DOM API,只能通过 postMessage() 传递序列化数据。这意味着它适合纯计算型任务(比如图像处理、加密),但不能用来“让 setTimeout 更快”或者“并发更新页面”。多数业务逻辑仍必须回到主线程协调。
真正容易被忽略的是:即使用了 Promise.all() 并发发起多个 fetch,这些请求在底层可能并行发出,但每个响应的 .then() 仍按微任务顺序串行进入调用栈——你无法靠 JS 代码本身实现真正的并行执行流。











