JavaScript单线程和任务队列是什么
JavaScript 单线程与任务队列详解
单线程模型
JavaScript 采用单线程执行模型,这意味着:
- 同一时间只能执行一个任务
- 代码按顺序执行,不会出现并行执行的情况
这种设计主要是为了避免复杂的线程同步问题(如死锁、竞态条件等),简化语言实现。
任务队列(Event Loop)机制
虽然 JavaScript 是单线程的,但通过事件循环(Event Loop)和任务队列机制实现了异步非阻塞的行为:
主要组成部分
调用栈(Call Stack)
任务队列(Task Queue)
- 存储待处理的异步任务回调
- 先进先出(FIFO)原则
事件循环(Event Loop)
- 不断检查调用栈是否为空
- 当调用栈为空时,从任务队列取出第一个任务推入调用栈执行
任务类型
宏任务(MacroTask)
- script 整体代码
- setTimeout/setInterval
- I/O 操作
- UI 渲染
- setImmediate(Node.js)
微任务(MicroTask)
- Promise.then/catch/finally
- MutationObserver
- process.nextTick(Node.js)
执行顺序
- 执行当前宏任务(如 script 代码)
- 执行过程中产生的微任务进入微任务队列
- 当前宏任务执行完毕后,立即执行所有微任务
- 微任务执行完毕后,进行 UI 渲染(浏览器环境)
- 从宏任务队列取出下一个宏任务执行
示例代码分析
console.log('1. 开始');
setTimeout(() => {
console.log('4. setTimeout 回调');
}, 0);
Promise.resolve().then(() => {
console.log('3. Promise 回调');
});
console.log('2. 结束');
输出顺序:
1. 开始
2. 结束
3. Promise 回调
4. setTimeout 回调
为什么需要这种机制
- 保持响应性:即使有长时间运行的任务,浏览器也不会完全冻结
- 高效处理 I/O:适合网络请求等异步操作
- 避免阻塞:通过回调机制实现非阻塞操作
实际应用注意事项
- 避免长时间运行的同步任务:会阻塞 UI 更新和其他任务执行
- 合理使用微任务:微任务会在当前宏任务结束后立即执行
- 理解执行顺序:特别是嵌套 Promise 和 setTimeout 的情况
理解 JavaScript 的单线程和任务队列机制对于编写高效、无阻塞的代码至关重要。