MST

星途 面试题库

面试题:网络编程:Node.js 中 Promise 如何处理多个异步操作并发执行

在 Node.js 后端开发的网络编程场景下,假设有多个需要同时发起的异步 I/O 操作(例如多个 HTTP 请求),请描述如何使用 Promise 来实现并发执行,并获取所有操作的结果。同时,说明可能会遇到的错误处理问题及解决方法。
10.5万 热度难度
后端开发网络编程

知识考点

AI 面试

面试题答案

一键面试

使用 Promise 实现并发执行并获取结果

在 Node.js 中,可以使用 Promise.all 方法来实现多个异步 I/O 操作的并发执行,并获取所有操作的结果。假设这些异步操作返回 Promise 对象,示例代码如下:

const axios = require('axios');

// 模拟多个 HTTP 请求
const requests = [
  axios.get('https://example.com/api1'),
  axios.get('https://example.com/api2'),
  axios.get('https://example.com/api3')
];

Promise.all(requests)
 .then((results) => {
    // results 是一个数组,按请求顺序包含每个请求的响应结果
    results.forEach((result, index) => {
      console.log(`Request ${index + 1} result:`, result.data);
    });
  })
 .catch((error) => {
    // 捕获任何一个请求失败的错误
    console.error('An error occurred:', error);
  });

在上述代码中:

  1. requests 数组包含多个返回 Promise 的异步操作(这里使用 axios 发起 HTTP 请求)。
  2. Promise.all 接收一个 Promise 数组作为参数,并返回一个新的 Promise。当所有传入的 Promise 都 resolved 时,新的 Promise 才会 resolved,并且其 resolved 值是一个数组,包含了每个传入 Promise 的 resolved 值,顺序与传入数组中的顺序一致。
  3. .then 回调函数接收 Promise.all 成功 resolved 的结果数组,对每个结果进行处理。
  4. .catch 回调函数捕获任何一个传入的 Promise 被 rejected 时的错误。

错误处理问题及解决方法

  1. 任何一个操作失败Promise.all 只要有一个 Promise 被 rejected,整个 Promise.all 就会被 rejected,并且 .catch 捕获到的是第一个被 rejected 的 Promise 的错误信息。这意味着即使其他操作可能已经成功完成,也无法在 .then 中获取到它们的结果。解决方法是可以在每个单独的 Promise 中进行更细粒度的错误处理,例如:
const requests = [
  axios.get('https://example.com/api1').catch(error => {
    console.error('Request 1 error:', error);
    return null; // 返回一个默认值,让 Promise.all 继续执行
  }),
  axios.get('https://example.com/api2').catch(error => {
    console.error('Request 2 error:', error);
    return null;
  }),
  axios.get('https://example.com/api3').catch(error => {
    console.error('Request 3 error:', error);
    return null;
  })
];

Promise.all(requests)
 .then((results) => {
    results.forEach((result, index) => {
      if (result) {
        console.log(`Request ${index + 1} result:`, result.data);
      }
    });
  })
 .catch((error) => {
    console.error('Overall error:', error);
  });

在这个改进版本中,每个请求的 catch 块捕获并处理单个请求的错误,返回一个默认值(这里是 null),这样即使某个请求失败,Promise.all 仍然可以继续执行并在 .then 中处理其他成功的结果。

  1. 错误传递与处理逻辑:在复杂的应用中,错误处理逻辑可能需要将错误信息传递给上层调用者或记录到日志系统。一种方法是在捕获错误后,重新抛出一个包含更多上下文信息的新错误,例如:
const requests = [
  axios.get('https://example.com/api1').catch(error => {
    const newError = new Error(`Request 1 failed: ${error.message}`);
    newError.originalError = error;
    throw newError;
  }),
  // 类似处理其他请求
];

Promise.all(requests)
 .catch((error) => {
    console.error('Error in Promise.all:', error.message);
    console.error('Original error:', error.originalError);
  });

这样可以在更上层的错误处理中获取到更详细的错误信息,便于调试和问题定位。