面试题答案
一键面试使用 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);
});
在上述代码中:
requests
数组包含多个返回 Promise 的异步操作(这里使用axios
发起 HTTP 请求)。Promise.all
接收一个 Promise 数组作为参数,并返回一个新的 Promise。当所有传入的 Promise 都 resolved 时,新的 Promise 才会 resolved,并且其 resolved 值是一个数组,包含了每个传入 Promise 的 resolved 值,顺序与传入数组中的顺序一致。.then
回调函数接收Promise.all
成功 resolved 的结果数组,对每个结果进行处理。.catch
回调函数捕获任何一个传入的 Promise 被 rejected 时的错误。
错误处理问题及解决方法
- 任何一个操作失败:
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
中处理其他成功的结果。
- 错误传递与处理逻辑:在复杂的应用中,错误处理逻辑可能需要将错误信息传递给上层调用者或记录到日志系统。一种方法是在捕获错误后,重新抛出一个包含更多上下文信息的新错误,例如:
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);
});
这样可以在更上层的错误处理中获取到更详细的错误信息,便于调试和问题定位。