Promise.all()使用场景

在上一节我们介绍了Promise.all()怎么样使用,这一部分我们思考一下什么场景下使用这个方法呢?
在等待多个Promise 完成的任何情况下,您都需要使用 Promise.all(),并且任何一次失败都会导致整个操作失败。 以下是 Promise.all() 的一些常见用例。
一起处理多个文件
在使用服务端 JavaScript 运行时(例如 Node.js 或 Deno)时,您可能需要读取多个文件并且处理其中包含的数据。 在这种情况下,并行读取文件并等到它们都被读取后再继续处理您检索到的数据是最有效的。
这是一个适用于 Node.js 的示例:
import { readFile } from "node:fs/promises";
function readFiles(filenames) {
return Promise.all(
filenames.map(filename => readFile(filename, "utf8"))
);
}
readFiles([
"file1.json",
"file2.json"
]).then(fileContents => {
// parse JSON data
const data = fileContents.map(
fileContent => JSON.parse(fileContent)
);
// process as necessary
console.log(data);
}).catch(reason => {
console.error(reason.message);
});
此示例使用基于 Node.js Promise的文件系统 API 来并行读取多个文件。 readFiles() 函数接受要读取的文件名数组,然后将每个文件名映射到由导入的 readFile() 函数创建的Promise。该文件被读取为文本(如作为第二个参数传递的“utf8”编码所示),结果在fullfilment handler中作为 fileContents 数组可用,数组中包含每个文件名对应的文本。 文件文本内容将作为 JSON 解析到数组中,然后传递给 processData() 函数。 这是跨多个文件处理数据的常用方法,因为如果无法读取或解析任何一个文件,则操作无法正确完成并应停止。
调用多个Web 服务 API
Promise.all() 的另一个常见用例是调用多个 Web 服务 API 时。 这在 REST API 中尤为常见,其中与实体关联的每种类型的数据都可能有自己的端点。 例如,考虑一个应用程序,其中每个用户都有博客文章和相册,您可能需要在用户的个人资料中收集所有这些信息。 代码可能如下所示:
const API_BASE = "https://jsonplaceholder.typicode.com";
function fetchUserData(userId) {
const urls = [
`${API_BASE}/users/${userId}/posts`,
`${API_BASE}/users/${userId}/albums`
];
return Promise.all(urls.map(url => fetch(url)));
}
fetchUserData(1).then(responses => {
return Promise.all(
responses.map(
response => {
if (response.ok) {
return response.json();
} else {
return Promise.reject(
new Error(`Unexpected status code: ${response.status} ${response.statusText} for ${response.url}`)
);
}
}
)
);
}).then(([posts, albums]) => {
// process your data as necessary
console.log(posts);
console.log(albums);
}).catch(reason => console.error(reason.message));
此示例使用 JSONPlaceholder¹ 服务,这是一个免费的虚假 API,用于测试和原型设计。 给定一个特定的用户 ID,JSONPlaceholder 将生成假数据。 在这种情况下,代码为每个用户提供/posts和/albums 端点。 fetchUserData() 函数接受用户 ID 并生成要调用的 URL。 然后将 URL 映射到每个 fetch() 调用返回的Promise。 当检索到响应时,另一个 Promise.all() 调用用于将每个响应映射到另一个 Promise,如果响应在 200-299 范围内,则为 JSON 正文,否则为拒绝的 Promise(这将使整个操作调用rejection handler)。 在最后一个settlement handler中,可以处理帖子和相册数据。