单线程与异步的关系
理解 JavaScript 单线程模型和异步机制的配合原理
问题
什么是单线程,和异步的关系?
解答
什么是单线程
单线程意味着 JavaScript 同一时间只能执行一个任务。所有代码在一个主线程上按顺序执行。
// 单线程执行:按顺序一行一行执行
console.log('1');
console.log('2');
console.log('3');
// 输出:1 2 3
为什么需要异步
如果所有操作都同步执行,遇到耗时任务(网络请求、定时器)会阻塞后续代码:
// 假设这是同步请求(实际会阻塞)
const data = syncRequest('/api/data'); // 等待 3 秒
console.log('继续执行'); // 3 秒后才执行,页面卡死
单线程如何实现异步
JavaScript 通过**事件循环(Event Loop)**实现异步。耗时任务交给浏览器其他线程处理,完成后将回调放入任务队列,主线程空闲时再执行。
console.log('1'); // 同步,立即执行
setTimeout(() => {
console.log('2'); // 异步,放入任务队列
}, 0);
Promise.resolve().then(() => {
console.log('3'); // 异步,放入微任务队列
});
console.log('4'); // 同步,立即执行
// 输出顺序:1 4 3 2
执行流程图解
// 主线程执行栈
// ┌─────────────────┐
// │ console.log(1) │ → 执行,输出 1
// │ setTimeout │ → 交给定时器线程,回调放入宏任务队列
// │ Promise.then │ → 回调放入微任务队列
// │ console.log(4) │ → 执行,输出 4
// └─────────────────┘
// ↓
// 执行栈清空,检查微任务队列
// ↓
// ┌─────────────────┐
// │ console.log(3) │ → 执行,输出 3
// └─────────────────┘
// ↓
// 微任务清空,检查宏任务队列
// ↓
// ┌─────────────────┐
// │ console.log(2) │ → 执行,输出 2
// └─────────────────┘
完整示例
console.log('script start');
setTimeout(() => {
console.log('setTimeout');
}, 0);
new Promise((resolve) => {
console.log('promise constructor'); // 同步执行
resolve();
}).then(() => {
console.log('promise then');
});
console.log('script end');
// 输出顺序:
// script start
// promise constructor
// script end
// promise then
// setTimeout
关键点
- 单线程:JS 主线程同一时间只能执行一个任务
- 异步不是多线程:异步任务由浏览器其他线程处理(定时器线程、网络线程),但回调仍在主线程执行
- 事件循环:主线程执行完同步代码后,从任务队列取出回调执行
- 微任务优先:Promise 回调(微任务)优先于 setTimeout 回调(宏任务)
- 不阻塞:异步让单线程能处理耗时操作而不卡死页面
目录