小伙伴们,你们好,“手写promise原理系列” 马上进入尾声了,我打算出到"手写promise原理系列九"便结束了。
为什么要出到系列九呢?大概是因为九这个数字吧!中国传统文化中,"十"是满盈之数,物极必反,盛极必衰,所以自谨待之;而"九"为百尺竿头更进一步,也希望自己能爬到百尺竿头,更进一步。九也为极之数,阳之数;在易经中,阳爻(yao)用九,阴爻用六,而乾卦为六个阳爻组成,《大象传》为乾卦立义为:天行健,君子以自强不息。
扯远了,回归正题。
当前章节探讨一下 Promise.all 方法的用法以及封装。
由 all
单词的释义我们可以知道是 全部
的意思,其实就是全部 promise 对象执行成功才返回结果,只要有一个失败,就返回失败的结果。
先来看失败的调用方式:
let p1 = new Promise((resolve, reject) => {
resolve("111");
});
let p2 = Promise.reject("222"); // 改变状态为失败 reject
let p3 = Promise.resolve("333");
let result = Promise.all([p1, p2, p3]); // 参数为 promise 对象组成的数组
console.log(result);
Promise.all 方法的参数是一个 promise 对象组成的数组,当 Promise.all 方法的参数中有一个失败的状态时,直接返回当前失败的 promise 对象的状态以及结果。
再来看同步执行成功的调用方式:
let p1 = new Promise((resolve, reject) => {
resolve("111");
});
let p2 = Promise.resolve("222");
let p3 = Promise.resolve("333");
let result = Promise.all([p1, p2, p3]);
console.log(result);
还有异步执行成功的调用方式:
let p1 = new Promise((resolve, reject) => {
setTimeout(()=>{
resolve("111");
}, 1000)
});
let p2 = Promise.resolve("222");
let p3 = Promise.resolve("333");
let result = Promise.all([p1, p2, p3]);
console.log(result);
由上面的同步、异步调用方式可知,不管 promise 对象是同步改变状态还是异步改变状态,Promise.all 的执行结果都是有序的。正常来说异步执行时,结果应该是"222"、"333"、"111"
,因为resolve("111")
是异步任务,在最后执行,他们三个的执行顺序应该是 p2–>p3–>p1。可是显示的结果却是 p1–>p2–>p3,这是为什么呢?
其实,关键点在于异步改变状态时,如何让 Promise.all 的执行结果变为有序的?很简单,在这里使用数组的下标赋值法,arr[1] = "222"; arr[2] = "333"; arr[0] = "111"
。这样得到的结果肯定是按顺序的 ["111", "222", "333"]
,因为根据数组下标来进行赋值操作时,就跟代码的执行顺序无关了。
let arr = new Array(3); // 创建 length 为3的空数组 arr
arr[1] = 222;
console.log(arr);
arr[2] = 333;
console.log(arr);
arr[0] = 111;
console.log(arr);
Promise.all 方法封装的代码:
Promise.all = function(promiseArray){
return new Promise((resolve, reject) => {
// 定义 Promise.all 方法的返回值
let arr = [];
// 循环处理 promise 对象
for(let i = 0; i < promiseArray.length; i++){
let p = promiseArray[i];
// 调用每一个 promise 对象的 then 方法,获取结果
p.then((value) => {
// 根据数组下标赋值,保证 promise 对象返回正确的结果
arr[i] = value;
// 判断是否所有的 promise 对象都执行完毕,若全部执行完毕,则返回结果
if (arr.length === promiseArray.length) {
resolve(arr);
}
}, reason => {
// 状态变为失败时,直接返回结果
reject(reason);
})
}
})
}