Promise API
JavaScript Promise API
As we have already stated, promises in JavaScript represent the eventual completion or failure of an asynchronous operation, as well as its resulting value. (如前所述, JavaScript中的promise表示异步操作的最终完成或失败,以及其结果值。)
The Promise class comprises five static methods. In this chapter, we cover all of them in detail. (Promise类包括五个静态方法。在本章中,我们将详细介绍所有这些内容。)
Promise.all
Promise.all
The Promise.all method is used when it is necessary to execute many promises at the same time and wait until all of them are ready. (当需要同时执行多个Promise并等待所有Promise准备就绪时,将使用Promise.all方法。)
For example, you intend to download several URLs in parallel, processing the content when all of them are done. (例如,您打算并行下载多个URL ,在所有URL完成后处理内容。)
The syntax of the Promise.all method is the following:
let promise = Promise.all([...promises...]);
It grabs an array of promises and returns a new promise. The new promise resolves at the time all the listed promises are settled. The array of their results becomes the result of it. (它抓取一系列Promise并返回一个新Promise。新承诺在所有列出的承诺结算时解决。他们的结果数组成为它的结果。)
Let’s examine the example below:
Promise.all([
new Promise(resolve => setTimeout(() => resolve(2), 3000)), // 2
(new Promise (resolve = > setTimeout (() = > resolve (2), 3000)),//2)
new Promise(resolve => setTimeout(() => resolve(4), 2000)), // 4
(new Promise (resolve = > setTimeout (() = > resolve (4), 2000)),//4)
new Promise(resolve => setTimeout(() => resolve(6), 1000)) // 6
]).then(console.log); // 2,4,6 when promises are ready: each promise is contributes an array member
Please, consider that the sequence of the resulting array members is equivalent to its source promises. Although the initial promise takes the longest time to resolve, it remains the first in the array of the results. (请考虑生成的数组成员的序列等同于其源Promise。虽然初始promise的解析时间最长,但它仍然是结果数组中的第一个。)
A usual trick is mapping an array of job data into an array of promises, and only then to wrap it into Promise.all. (通常的诀窍是将作业数据数组映射到Promise数组中,然后将其包装到Promise.all中。)
In the example below, there is an array of URLs that is fetched as follows:
let urls = [
'https://api.github.com/users/User1',
'https://api.github.com/users/User2',
'https://api.github.com/users/User3'
];
// map each url to the promise of the fetch
let requests = urls.map(url => fetch(url));
// Promise.all is waiting for all jobs to resolve
Promise.all(requests)
.then(responses => responses.forEach(
(.then (responses = > responses.forEach ()
response => console.log(`${response.url}: ${response.status}`)
));
And, here is 1,2,3 when the promises are ready: each promise is contributed by an array member a larger example:
let names = ['User1', 'User2', 'User3'];
let requests = names.map(name => fetch(`https://api.github.com/users/${name}`));
Promise.all(requests)
.then(responses => {
// all responses successfully resolved
(//已成功解析所有回复)
for (let response of responses) {
console.log(`${response.url}: ${response.status}`); // shows 200 for every url
}
return responses;
})
// map the responses array to the response.json() array to read their content
(//将响应数组映射到response.json ()数组以读取其内容)
.then(responses => Promise.all(responses.map(res => res.json())))
(.then (responses = > Promise.all (responses.map (res = > res.json ()))))
// all JSON answers are parsed: "users" is their array
.then(users => users.forEach(user => console.log(user.name)));
In case any promise is rejected, the one that is returned by Promise.all rejects with that error at once. (如果任何Promise被拒绝, Promise.all返回的Promise会立即拒绝该错误。)
For example:
Promise.all([
new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)),
(new Promise ((resolve, reject) = > setTimeout (() = > resolve (1), 1000)),)
new Promise((resolve, reject) => setTimeout(() => reject(new Error("Error!!")), 2000)),
(new Promise ((resolve, reject) = > setTimeout (() = > reject (new Error ("Error!!")), 2000)),)
new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000))
]).catch(console.log); // Error: Error!!
In the example above, the second promise rejects in two seconds. It moves to the immediate rejection of Promise.all. Consequently, .catch executes, and the rejection error becomes the outcome of the whole Promise.all. (在上面的示例中,第二个promise在两秒钟内拒绝。它转向立即拒绝Promise.all。因此, .catch执行,拒绝错误成为整个Promise.all的结果。)
Note that, if an error occurs, other promises are ignored. (>请注意,如果发生错误,其他承诺将被忽略。)
So, in case a promise rejects, Promise.all also rejects immediately, forgetting about the other promises in the list. Their result will be ignored, as well. (因此,如果promise拒绝, Promise.all也会立即拒绝,忘记列表中的其他promise。他们的结果也将被忽略。)
Imagine that you have multiple fetch calls, and one of them fails: the others will go on executing, but Promise.all will not look them up any longer. Probably, they will be settled, but their results will be ignored.
Promise.all(iterable) enables non-promise “regular” values inside an iterable. (Promise.all (可迭代)在可迭代内启用非Promise “常规”值。)
Yet, of any of those objects is not a promise, it will pass to the resulting array “as is”. (然而,这些对象中的任何一个都不是promise ,它将“按原样”传递给结果数组。)
Here is an example:
Promise.all([
new Promise((resolve, reject) => {
setTimeout(() => resolve(2), 1000)
(setTimeout (() = > resolve (2), 1000))
}),
4,
6
]).then(console.log); // 2, 4, 6
Promise.allSettled
Promise.allSettled
The Promise.allSettled method is used for returning a promise, which resolves after all of the given promises have resolved or rejected, along with an array of objects that each describe each promise’s outcome. (Promise.allSettled方法用于返回一个promise ,该promise在所有给定promise已解析或已拒绝后解析,同时返回一个对象数组,每个对象描述每个promise的结果。)
Let’s check out examples demonstrating the differences between the Promise.all and Promise.allSettled methods. (让我们查看演示Promise.all和Promise.allSettled方法之间差异的示例。)
For instance, Promise.all rejects as a whole in case any of the promises rejects:
Promise.all([
fetch('/index.html'),
(fetch ('/index.html'),)
fetch('/style.css'),
(fetch ('/style.css'),)
fetch('/data.json')
]).then(render); // the render method needs the results of all fatches
let urls = [
'https://api.github.com/users/User1',
'https://api.github.com/users/User2',
'https://noSuchUrl'
];
Promise.allSettled(urls.map(url => fetch(url)))
.then(results => { // (*)
results.forEach((result, number) => {
if (result.status == "fulfilled") {
console.log(`${urls[number]}: ${result.value.status}`);
}
if (result.status == "rejected") {
console.log(`${urls[number]}: ${result.reason}`);
}
});
});
The result in the line (*) will be the following:
[{ status: 'fulfilled', value: ...response... }, { status: 'fulfilled', value: ...response... }, { status: 'rejected', reason: ...error object... } ]
For each promise you will get its status and value/error. (对于每个承诺,您将获得其状态和值/错误。)
Polyfill
Polyfill
In case your browser doesn’t support Promise.allSettled, you can polyfill it using this code:
if (!Promise.allSettled) {
Promise.allSettled = function (promises) {
return Promise.all(promises.map(p => Promise.resolve(p).then(value => ({
state: 'fulfilled',
value
(值)
}), reason => ({
state: 'rejected',
reason
(成因)
}))));
};
}
Promise.race
Promise.race
Promise.race is similar to Promise.all. The difference is that it waits only for the initial promise settled and then gets either the result or the error of it. (Promise.race类似于Promise.all。不同之处在于,它只等待初始promise结算,然后获取其结果或错误。)
Its syntax looks like this:
let promise = Promise.race(iterable);
Here, the result will be 1:
Promise.race([
new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)),
(new Promise ((resolve, reject) = > setTimeout (() = > resolve (1), 1000)),)
new Promise((resolve, reject) => setTimeout(() => reject(new Error("Error!!")), 2000)),
(new Promise ((resolve, reject) = > setTimeout (() = > reject (new Error ("Error!!")), 2000)),)
new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000))
]).then(console.log); // 1
So, in the example above, the initial promise was the fastest one; hence it became the result.
Promise.resolve/reject
Promise.resolve/reject
Promise.resolve and Promise.reject methods are not used often in modern codes, as the async/await syntax makes them outdated. They are useful when it is not possible to use async/await. (Promise.resolve和Promise.reject方法在现代代码中不经常使用,因为async/await语法使它们过时。当无法使用async/await时,它们非常有用。)
Promise.resolve
Promise.resolve
This method is aimed at creating a resolved promise with the result value. (此方法旨在使用结果值创建已解决的承诺。)
It’s the same as this:
let promise = new Promise(resolve => resolve(value));
This method is generally used for compatibility, whenever a function is expected to return a promise. (每当期望函数返回promise时,此方法通常用于兼容性。)
Promise Reject
Promise Reject (拒绝承诺)
The Promise.reject method is used for creating a rejected promise with an error. (Promise.reject方法用于创建出现错误的已拒绝承诺。)
It’s the same as:
let promise = new Promise((resolve, reject) => reject(error));
This method is almost never used in practice. (这种方法在实践中几乎从未使用过。)
Summary
Summary (概要)
Promises allow associating handlers with an asynchronous action’s eventual success value or failure reason. (Promise允许将处理程序与异步操作的最终成功值或失败原因相关联。)
Promise class has five static methods: Promise.all(promises), Promise.allSettled(promises),Promise.race(promises), Promise.resolve(value) and promise.reject(error).
Of the mentioned above five methods, the most common in practice is Promise.all.. (在上述五种方法中,实践中最常见的是Promise.all..)