响应多个 Promise
本章至今的每个例子在同一时刻都只响应一个 Promise。然而有时你会想监视多个 Promise 的进程,以便决定下一步行动。ES6 提供了能监视多个 Promise 的两个方法:Promise.all() 与 Promise.race()。
Promise.all() 方法
Promise.all() 方法接收单个可迭代对象(如数组)作为参数,并返回一个 Promise。这个可迭代对象的元素都是 Promise,只有在它们都完成后,所返回的 Promise 才会被完成。例如:
译注:原文在此处有貌似重复的描述,相似的话语用被决议(resolved)、被完成(fulfilled) 这两个术语说了两次,而这两个词在 Promise 中基本是同一个意思,因此译文删掉了其中一句。 |
let p1 = new Promise(function(resolve, reject) {
resolve(42);
});
let p2 = new Promise(function(resolve, reject) {
resolve(43);
});
let p3 = new Promise(function(resolve, reject) {
resolve(44);
});
let p4 = Promise.all([p1, p2, p3]);
p4.then(function(value) {
console.log(Array.isArray(value)); // true
console.log(value[0]); // 42
console.log(value[1]); // 43
console.log(value[2]); // 44
});
此处前面的每个 Promise 都用一个数值进行了决议,对 Promise.all() 的调用创建了新的 Promise p4,在 p1、p2 与 p3 都被完成后,p4 最终会也被完成。传递给 p4 的完成处理函数的结果是一个包含每个决议值(42、43 与 44)的数组,这些值的存储顺序保持了待决议的 Promise 的顺序(与完成的先后顺序无关),因此你可以将结果匹配到每个 Promise。
若传递给 Promise.all() 的任意 Promise 被拒绝了,那么方法所返回的 Promise 就会立刻被拒绝,而不必等待其他的 Promise 结束:
let p1 = new Promise(function(resolve, reject) {
resolve(42);
});
let p2 = new Promise(function(resolve, reject) {
reject(43);
});
let p3 = new Promise(function(resolve, reject) {
resolve(44);
});
let p4 = Promise.all([p1, p2, p3]);
p4.catch(function(value) {
console.log(Array.isArray(value)) // false
console.log(value); // 43
});
在此例中,p2 被使用数值 43 进行了拒绝,则 p4 的拒绝处理函数就立刻被调用, 而不会等待 p1 或 p3 结束执行(它们仍然会各自结束执行,只是 p4 不等它们)。
拒绝处理函数总会接收到单个值,而不是一个数组,该值就是被拒绝的 Promise 所返回的拒绝值。本例中的拒绝处理函数被传入了 43,反映了来自 p2 的拒绝。
Promise.race() 方法
Promise.race() 提供了监视多个 Promise 的一个稍微不同的方法。此方法也接受一个包含需监视的 Promise 的可迭代对象,并返回一个新的 Promise,但一旦来源 Promise 中有一个被解决,所返回的 Promise 就会立刻被解决。与等待所有 Promise 完成的 Promise.all() 方法不同,在来源 Promise 中任意一个被完成时,Promise.race() 方法所返回的 Promise 就能作出响应。例如:
let p1 = Promise.resolve(42);
let p2 = new Promise(function(resolve, reject) {
resolve(43);
});
let p3 = new Promise(function(resolve, reject) {
resolve(44);
});
let p4 = Promise.race([p1, p2, p3]);
p4.then(function(value) {
console.log(value); // 42
});
在此代码中,p1 被创建为一个已完成的 Promise,而其他的 Promise 则需要调度作业。p4 的完成处理函数被使用数值 42 进行了调用,并忽略了其他的 Promise。传递给 Promise.race() 的 Promise 确实在进行赛跑,看哪一个首先被解决。若胜出的 Promise 是被完成,则返回的新 Promise 也会被完成;而胜出的 Promise 若是被拒绝,则新 Promise 也会被拒绝。此处有个使用拒绝的范例:
let p1 = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(42);
}, 100);
});
let p2 = new Promise(function(resolve, reject) {
reject(43);
});
let p3 = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(44);
}, 50);
});
let p4 = Promise.race([p1, p2, p3]);
p4.catch(function(value) {
console.log(value); // 43
});
此处的 p4 被拒绝了,因为 p2 在 Promise.race() 被调用时已经处于拒绝态。尽管 p1 与 p3 都被完成,其结果仍然被忽略,因为这发生在 p2 被拒绝之后。
译注:此处范例有误。 在各个浏览器中的测试结果都是没有任何输出;而若为 p4 添加一个类似的完成处理函数,则会输出 42。这表示在赛跑中胜出的是 p1 而不是 p2。 如果要让此范例正确,应当在 p1 与 p3 内部的 resolve() 上添加延时处理。 |