Promise.all 的使用、原理实现及错误处理
使用方式
Promise.all()方法将多个 Promise 实例包装成一个 Promise 对象(p),接受一个数组(p1,p2,p3)作为参数,数组中不一定需要都是 Promise 对象,但是一定具有 Iterator 接口,如果不是的话,就会调用 Promise.resolve 将其转化为 Promise 对象之后再进行处理。使用 Promise.all()生成的 Promise 对象(p)的状态是由数组中的 Promise 对象(p1,p2,p3)决定的;
- 如果所有的 Promise 对象(p1,p2,p3)都变成 fullfilled 状态的话,生成的 Promise 对象(p)也会变成 fullfilled 状态,p1,p2,p3 三个 Promise 对象产生的结果会组成一个数组返回给传递给 p 的回调函数;
- 如果 p1,p2,p3 中有一个 Promise 对象变为 rejected 状态的话,p 也会变成 rejected 状态,第一个被 rejected 的对象的返回值会传递给 p 的回调函数。
- Promise.all()方法生成的 Promise 对象也会有一个 catch 方法来捕获错误处理,但是如果数组中的 Promise 对象变成 rejected 状态时,并且这个对象还定义了 catch 的方法,那么 rejected 的对象会执行自己的 catch 方法,并且返回一个状态为 fullfilled 的 Promise 对象,Promise.all()生成的对象会接受这个 Promise 对象,不会返回 rejected 状态。
// 以下 demo,请求两个 url,当两个异步请求返还结果后,再请求第三个 url
const p1 = request(`http://some.url.1`);
const p2 = request(`http://some.url.2`);
Promise.all([p1, p2])
.then((datas) => {
// 此处 datas 为调用 p1, p2 后的结果的数组
return request(`http://some.url.3?a=${datas[0]}&b=${datas[1]}`);
})
.then((data) => {
console.log(msg);
});
实现
function promiseAll(promises) {
return new Promise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError("argument must be an array"));
}
let countNum = 0;
let promiseNum = promises.length;
let resolvedvalue = new Array(promiseNum);
// for (var i = 0; i < promiseNum; i++) {
// (function (i) {
// Promise.resolve(promises[i]).then(
// function (value) {
// countNum++;
// resolvedvalue[i] = value;
// if (countNum === promiseNum) {
// return resolve(resolvedvalue);
// }
// },
// function (reason) {
// return reject(reason);
// }
// );
// })(i);
// }
promises.map((promise, i) => {
Promise.resolve(promise).then(
(val) => {
countNum++;
resolvedvalue[i] = val;
if (countNum === promiseNum) {
resolve(resolvedvalue);
}
},
(err) => {
reject(err);
}
);
});
});
}
let p1 = Promise.resolve(1),
p2 = Promise.resolve(2),
p3 = Promise.resolve(3);
promiseAll([p1, p2, p3]).then(function (value) {
console.log(value); // [ 1, 2, 3 ]
});
错误处理
在有一个 promise 出错的情况下 promise.all 仍然能返回其他正确数据
var p1 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(1);
}, 0);
});
var p2 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(2);
}, 200);
});
var p3 = new Promise(function (resolve, reject) {
setTimeout(function () {
try {
console.log(XX.BBB);
} catch (exp) {
resolve("error");
}
}, 100);
});
Promise.all([p1, p2, p3])
.then(function (results) {
console.log("success");
console.log(results);
})
.catch(function (r) {
console.log("err");
console.log(r);
});
//success
//[ 1, 2, 'error' ]