1. 执行顺序
- 事件循环机制:Node.js 基于事件循环来处理异步操作。事件循环会不断检查调用栈是否为空,当调用栈为空时,会从任务队列中取出任务放入调用栈执行。
- 宏任务队列:常见的宏任务包括
setTimeout
、setInterval
、setImmediate
、I/O
操作等。事件循环每次从宏任务队列中取出一个宏任务执行,执行完毕后,会检查微任务队列。
- 微任务队列:常见的微任务有 Promise 的回调(
.then
、.catch
)、process.nextTick
等。微任务会在当前宏任务执行结束后,下一个宏任务开始之前执行。也就是说,事件循环在执行完一个宏任务后,会清空微任务队列中的所有微任务,然后再从宏任务队列中取下一个宏任务执行。
2. 错误传播和处理机制
- 宏任务错误:宏任务中的错误通常不会直接影响其他宏任务或微任务。例如,
setTimeout
回调中的错误不会导致后续的 setTimeout
回调或其他宏任务无法执行。如果宏任务中的错误没有被捕获,它会在该宏任务的作用域内抛出,可能会导致当前进程或线程出现问题(如 Node.js 进程崩溃),具体取决于运行环境。
- 微任务错误:微任务中的错误会中断微任务队列的执行。如果一个 Promise 的
.then
回调中抛出错误,后续的 .then
回调将不会执行,而是直接进入 .catch
回调。如果没有 .catch
回调,错误会向上传播到全局的 unhandledRejection
事件(在 Node.js 中),可能导致应用出现未处理的拒绝情况。
3. 确保错误妥善处理,避免应用崩溃
- 宏任务错误处理:
- 使用
try - catch
:在宏任务回调内部使用 try - catch
块捕获错误,例如:
setTimeout(() => {
try {
// 可能出错的代码
throw new Error('宏任务中的错误');
} catch (error) {
console.error('捕获宏任务中的错误:', error);
}
}, 0);
- 监听全局错误事件:在 Node.js 中,可以监听
uncaughtException
事件来捕获未处理的异常,避免进程崩溃:
process.on('uncaughtException', (error) => {
console.error('捕获全局未处理的宏任务异常:', error);
});
- 微任务错误处理:
- 使用
.catch
处理 Promise 错误:在每个 Promise 链中,确保有 .catch
回调来处理可能的错误:
Promise.resolve()
.then(() => {
throw new Error('微任务中的错误');
})
.catch((error) => {
console.error('捕获微任务中的错误:', error);
});
- 监听
unhandledRejection
事件:在 Node.js 中,监听 unhandledRejection
事件来处理未处理的 Promise 拒绝:
process.on('unhandledRejection', (reason, promise) => {
console.error('捕获未处理的微任务拒绝:', reason, promise);
});
- 使用
async/await
结合 try - catch
:在 async
函数中使用 try - catch
捕获错误,因为 await
会暂停函数执行,直到 Promise 被解决,所以可以很好地捕获错误:
async function asyncFunction() {
try {
await Promise.reject(new Error('微任务中的错误'));
} catch (error) {
console.error('捕获微任务中的错误:', error);
}
}
asyncFunction();