MST
星途 面试题库

面试题:JavaScript 在 Node 默认异步下的错误处理机制与最佳实践

在一个复杂的 Node.js 项目中,多个异步操作相互依赖且可能会抛出不同类型的错误。阐述如何建立一个统一且高效的错误处理机制,使其能够捕获并合理处理这些异步操作中的错误,同时兼顾代码的可读性和维护性。例如一个包含数据库查询、文件读取和网络请求的业务逻辑。
33.0万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试

1. 使用 async/await 结合 try/catch

在 Node.js 中,async/await 是处理异步操作的一种简洁方式,结合 try/catch 可以有效地捕获异步操作中抛出的错误。

示例代码

async function complexOperation() {
  try {
    // 数据库查询
    const dbResult = await databaseQuery();
    // 文件读取
    const fileContent = await readFile();
    // 网络请求
    const networkResponse = await networkRequest(dbResult, fileContent);
    return networkResponse;
  } catch (error) {
    // 统一处理所有错误
    handleError(error);
  }
}

function databaseQuery() {
  // 模拟数据库查询
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      Math.random() > 0.5? resolve('Database result') : reject(new Error('Database query error'));
    }, 1000);
  });
}

function readFile() {
  // 模拟文件读取
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      Math.random() > 0.5? resolve('File content') : reject(new Error('File read error'));
    }, 1000);
  });
}

function networkRequest(dbResult, fileContent) {
  // 模拟网络请求
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      Math.random() > 0.5? resolve('Network response') : reject(new Error('Network request error'));
    }, 1000);
  });
}

function handleError(error) {
  // 根据错误类型进行不同处理
  if (error.message.includes('Database')) {
    console.error('数据库错误:', error.message);
  } else if (error.message.includes('File')) {
    console.error('文件错误:', error.message);
  } else if (error.message.includes('Network')) {
    console.error('网络错误:', error.message);
  } else {
    console.error('未知错误:', error.message);
  }
}

2. 自定义错误类

为了更好地区分不同类型的错误,可以自定义错误类。这样在捕获错误时,可以根据错误类型进行更细致的处理。

示例代码

class DatabaseError extends Error {
  constructor(message) {
    super(message);
    this.name = 'DatabaseError';
  }
}

class FileError extends Error {
  constructor(message) {
    super(message);
    this.name = 'FileError';
  }
}

class NetworkError extends Error {
  constructor(message) {
    super(message);
    this.name = 'NetworkError';
  }
}

async function complexOperation() {
  try {
    // 数据库查询
    const dbResult = await databaseQuery();
    // 文件读取
    const fileContent = await readFile();
    // 网络请求
    const networkResponse = await networkRequest(dbResult, fileContent);
    return networkResponse;
  } catch (error) {
    // 统一处理所有错误
    handleError(error);
  }
}

function databaseQuery() {
  // 模拟数据库查询
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      Math.random() > 0.5? resolve('Database result') : reject(new DatabaseError('Database query error'));
    }, 1000);
  });
}

function readFile() {
  // 模拟文件读取
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      Math.random() > 0.5? resolve('File content') : reject(new FileError('File read error'));
    }, 1000);
  });
}

function networkRequest(dbResult, fileContent) {
  // 模拟网络请求
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      Math.random() > 0.5? resolve('Network response') : reject(new NetworkError('Network request error'));
    }, 1000);
  });
}

function handleError(error) {
  // 根据错误类型进行不同处理
  if (error instanceof DatabaseError) {
    console.error('数据库错误:', error.message);
  } else if (error instanceof FileError) {
    console.error('文件错误:', error.message);
  } else if (error instanceof NetworkError) {
    console.error('网络错误:', error.message);
  } else {
    console.error('未知错误:', error.message);
  }
}

3. 错误中间件(适用于 Express 等框架)

如果项目基于 Express 等框架,可以利用错误中间件来统一处理错误。

示例代码

const express = require('express');
const app = express();

app.get('/complex', async (req, res, next) => {
  try {
    // 数据库查询
    const dbResult = await databaseQuery();
    // 文件读取
    const fileContent = await readFile();
    // 网络请求
    const networkResponse = await networkRequest(dbResult, fileContent);
    res.send(networkResponse);
  } catch (error) {
    next(error);
  }
});

// 错误中间件
app.use((err, req, res, next) => {
  // 根据错误类型进行不同处理
  if (err.message.includes('Database')) {
    res.status(500).send('数据库错误:' + err.message);
  } else if (err.message.includes('File')) {
    res.status(500).send('文件错误:' + err.message);
  } else if (err.message.includes('Network')) {
    res.status(500).send('网络错误:' + err.message);
  } else {
    res.status(500).send('未知错误:' + err.message);
  }
});

function databaseQuery() {
  // 模拟数据库查询
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      Math.random() > 0.5? resolve('Database result') : reject(new Error('Database query error'));
    }, 1000);
  });
}

function readFile() {
  // 模拟文件读取
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      Math.random() > 0.5? resolve('File content') : reject(new Error('File read error'));
    }, 1000);
  });
}

function networkRequest(dbResult, fileContent) {
  // 模拟网络请求
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      Math.random() > 0.5? resolve('Network response') : reject(new Error('Network request error'));
    }, 1000);
  });
}

const port = 3000;
app.listen(port, () => {
  console.log(`Server running on port ${port}`);
});

通过以上方法,可以建立一个统一且高效的错误处理机制,提高代码的可读性和维护性。