使用 JavaScript Promise 并行处理多个请求
笔记+分享
在现代Web开发中,处理多个异步请求并行是一个常见需求。JavaScript中的Promise提供了一种强大的机制来管理这些并行操作。本文将详细介绍如何使用Promise.all
和Promise.allSettled
来实现这一点,并提供一些实用的示例代码。
Promise.all 和 Promise.allSettled
在处理多个并行请求时,最常用的两个Promise方法是Promise.all
和Promise.allSettled
。
Promise.all
Promise.all
方法接收一个Promise数组,当所有Promise都成功时,返回一个包含所有结果的数组。如果任何一个Promise失败,整个Promise.all
都会立即失败,并抛出第一个失败的Promise的错误。
const promise1 = new Promise((resolve) => {setTimeout(() => resolve('Promise 1 resolved'), 1000);
});const promise2 = new Promise((resolve) => {setTimeout(() => resolve('Promise 2 resolved'), 2000);
});const promise3 = new Promise((_, reject) => {setTimeout(() => reject('Promise 3 rejected'), 1500);
});Promise.all([promise1, promise2, promise3]).then(results => {console.log(results); // 不会执行}).catch(error => {console.error(error); // 输出: Promise 3 rejected});
在这个例子中,Promise.all
因为promise3
被拒绝而失败,导致整个操作被短路。
Promise.allSettled
相比之下,Promise.allSettled
方法会等待所有Promise都完成,无论是成功还是失败。它返回一个包含每个Promise结果对象的数组,每个结果对象都有一个status
属性(“fulfilled"或"rejected”)和相应的value
或reason
属性。
Promise.allSettled([promise1, promise2, promise3]).then(results => {results.forEach((result, index) => {if (result.status === 'fulfilled') {console.log(`Promise ${index + 1} fulfilled with value: ${result.value}`);} else {console.error(`Promise ${index + 1} rejected with reason: ${result.reason}`);}});});
在这个例子中,所有Promise的状态都会被处理,无论它们是成功还是失败。
使用 Promise.all 实现错误处理
虽然Promise.allSettled
可以处理所有Promise的结果,无论它们是否成功或失败,但有时我们更希望使用Promise.all
,但又不想因为某个Promise失败而导致所有Promise都被短路。为了解决这个问题,我们可以通过在每个Promise周围添加一个错误处理逻辑来实现。这可以通过在每个Promise后添加.catch
来捕获错误并返回一个标记为失败的结果对象。
包装 Promise 以处理错误
我们可以创建一个包装函数,确保所有Promise都能执行,并返回一个包含结果和错误的数组。
const handlePromise = (promise) => {return promise.then(result => ({ status: 'fulfilled', value: result })).catch(error => ({ status: 'rejected', reason: error }));
};const fetchUser = fetch('https://api.example.com/user').then(res => res.json());
const fetchPosts = fetch('https://api.example.com/posts').then(res => res.json());
const fetchComments = fetch('https://api.example.com/comments').then(res => res.json());Promise.all([handlePromise(fetchUser),handlePromise(fetchPosts),handlePromise(fetchComments)
])
.then(results => {results.forEach((result, index) => {if (result.status === 'fulfilled') {console.log(`Request ${index + 1} succeeded with value:`, result.value);} else {console.error(`Request ${index + 1} failed with reason:`, result.reason);}});
});
详细示例
假设我们有三个并行的API请求,即使其中一个请求失败,我们仍然希望其他请求能够完成并处理它们的结果或错误。
const handlePromise = (promise) => {return promise.then(result => ({ status: 'fulfilled', value: result })).catch(error => ({ status: 'rejected', reason: error }));
};// 示例请求
const fetchUser = fetch('https://api.example.com/user').then(response => {if (!response.ok) {throw new Error('Failed to fetch user');}return response.json();
});const fetchPosts = fetch('https://api.example.com/posts').then(response => {if (!response.ok) {throw new Error('Failed to fetch posts');}return response.json();
});const fetchComments = fetch('https://api.example.com/comments').then(response => {if (!response.ok) {throw new Error('Failed to fetch comments');}return response.json();
});// 使用 Promise.all 执行所有请求
Promise.all([handlePromise(fetchUser),handlePromise(fetchPosts),handlePromise(fetchComments)
])
.then(results => {results.forEach((result, index) => {if (result.status === 'fulfilled') {console.log(`Request ${index + 1} succeeded with value:`, result.value);} else {console.error(`Request ${index + 1} failed with reason:`, result.reason);}});
});
解析
handlePromise
函数:该函数接收一个Promise,并在Promise解析或拒绝时返回一个标准化的对象,包含status
、value
或reason
。- 并行请求:每个请求通过
fetch
方法发起,并附带错误处理。如果请求失败,抛出一个错误。 - Promise.all:使用
Promise.all
并行执行所有经过handlePromise
包装的请求。即使其中一个或多个请求失败,所有请求都会继续执行。 - 结果处理:在
then
方法中,遍历所有结果,根据status
属性分别处理成功和失败的请求。
总结
通过这种方式,使用Promise.all
时,可以确保所有Promise都能执行,无论其中某些Promise是否失败。这在处理多个并行请求时非常有用,可以确保即使某些请求失败,也能获取其他请求的结果,从而提高代码的健壮性和可靠性。希望本文的介绍和示例代码能够帮助你更好地理解和使用JavaScript中的Promise来管理并行请求。
通过这种方式,开发者可以更灵活地处理并行请求,无论是使用Promise.all
还是Promise.allSettled
,都能够确保在复杂的异步操作中更加健壮地管理请求结果。