面试题答案
一键面试1. try - catch
- 优点:
- 同步代码友好:在同步代码块中,
try - catch
能够简洁明了地捕获代码执行过程中抛出的异常,将错误处理代码与正常业务代码紧密结合,使得错误处理逻辑清晰。例如:
- 同步代码友好:在同步代码块中,
try {
let result = 1 / 0; // 会抛出异常
console.log(result);
} catch (error) {
console.log('捕获到错误:', error.message);
}
- **作用域明确**:只捕获 `try` 块内抛出的错误,不会影响外部代码执行,对代码的隔离性较好,不会干扰到其他模块或代码段。
- 缺点:
- 异步代码无力:无法捕获异步操作(如
setTimeout
、Promise
等)中抛出的异常。例如:
- 异步代码无力:无法捕获异步操作(如
try {
setTimeout(() => {
let result = 1 / 0; // 这里抛出的异常不会被 try - catch 捕获
console.log(result);
}, 1000);
} catch (error) {
console.log('捕获到错误:', error.message);
}
- **嵌套复杂**:当存在多层嵌套的异步操作时,若要捕获每个操作的异常,需要在每层都添加 `try - catch`,代码变得冗长且可读性差。
2. process.on('uncaughtException')
- 优点:
- 全局捕获:可以捕获整个进程中未被捕获的异常,对于保障应用程序在遇到严重错误时不至于突然崩溃有很大帮助,能提供最后的防护机制。例如,在一个 HTTP 服务器应用中,即使某个请求处理逻辑中抛出了未捕获的异常,通过这个机制可以记录错误日志并保持服务器继续运行。
process.on('uncaughtException', (error) => {
console.log('全局捕获到未处理异常:', error.message);
// 可以在这里做一些清理工作,如关闭数据库连接等
});
let result = 1 / 0; // 会触发全局捕获
- 缺点:
- 难以定位:由于是全局捕获,很难精确知道错误具体发生在哪个模块或哪段代码中,不利于调试,特别是在大型项目中。
- 影响执行:捕获异常后,如果没有妥善处理,可能会导致进程处于不稳定状态,后续代码执行可能会出现不可预料的问题,因为异常发生时,程序的执行状态已经被破坏。
3. Domain 模块
- 优点:
- 异步支持:能够捕获异步操作中的异常,弥补了
try - catch
在异步方面的不足。例如,在处理多个异步 I/O 操作时,可以将相关操作放在同一个Domain
中,确保所有异步操作的异常都能被捕获。
- 异步支持:能够捕获异步操作中的异常,弥补了
const domain = require('domain');
const d = domain.create();
d.on('error', (error) => {
console.log('Domain 捕获到错误:', error.message);
});
d.run(() => {
setTimeout(() => {
let result = 1 / 0; // 会被 Domain 捕获
console.log(result);
}, 1000);
});
- **代码组织**:有助于将相关的异步操作及其错误处理组织在一起,增强了代码的逻辑性和可读性,尤其适用于复杂的异步业务逻辑。
- 缺点:
- 已弃用:在 Node.js v14.13.1 版本开始被标记为弃用,未来可能不再得到支持,所以新项目中不建议使用。
- 增加复杂性:使用
Domain
模块需要额外引入概念和代码结构,对于简单项目可能增加不必要的复杂性。
4. 业务场景选择
- 同步业务场景:
- 选择:优先使用
try - catch
。 - 示例:在进行简单的数学计算、数据验证等同步操作时,
try - catch
可以直接捕获异常。比如一个函数用于解析 JSON 字符串:
- 选择:优先使用
function parseJSON(str) {
try {
return JSON.parse(str);
} catch (error) {
console.log('解析 JSON 错误:', error.message);
return null;
}
}
let jsonStr = '{invalid json}';
let result = parseJSON(jsonStr);
- 异步业务场景(非大型复杂项目):
- 选择:如果使用
Promise
,可以使用.catch
方法处理异常;对于setTimeout
等简单异步操作,也可以考虑将其包装在一个函数内,再用try - catch
捕获。 - 示例:使用
Promise
读取文件内容:
- 选择:如果使用
const fs = require('fs').promises;
fs.readFile('nonexistentfile.txt', 'utf8')
.then(data => console.log(data))
.catch(error => console.log('读取文件错误:', error.message));
- 异步业务场景(大型复杂项目):
- 选择:结合使用
try - catch
(在同步部分)、.catch
(在Promise
链中)和process.on('uncaughtException')
。对于一些特定的、关联性强的异步操作组,可以考虑使用async/await
结合try - catch
来处理异常,它能以同步的方式书写异步代码,同时方便捕获异常。对于整个应用程序的兜底保护,使用process.on('uncaughtException')
记录错误日志等操作。 - 示例:在一个大型的电商后台服务中,处理订单创建的复杂业务逻辑,涉及多个数据库操作、外部 API 调用等异步操作,使用
async/await
结合try - catch
:
- 选择:结合使用
async function createOrder(orderData) {
try {
// 数据库操作 1
await saveOrderToDB(orderData);
// 外部 API 调用
await callPaymentAPI(orderData);
// 数据库操作 2
await updateInventory(orderData);
return '订单创建成功';
} catch (error) {
console.log('创建订单过程中出现错误:', error.message);
// 进行错误处理,如回滚数据库操作等
return '订单创建失败';
}
}
同时,在应用程序入口添加 process.on('uncaughtException')
来捕获可能遗漏的未处理异常:
process.on('uncaughtException', (error) => {
console.log('全局捕获到未处理异常:', error.message);
// 记录错误日志到文件
});