第 80 题:介绍下 Promise.all 使用、原理实现及错误处理
zeroone001 opened this issue · 44 comments
const p = Promise.all([p1, p2, p3]);Promise.all方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。(Promise.all方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。)
哦
all(list) {
return new Promise((resolve, reject) => {
let resValues = [];
let counts = 0;
for (let [i, p] of list) {
resolve(p).then(res => {
counts++;
resValues[i] = res;
if (counts === list.length) {
resolve(resValues)
}
}, err => {
reject(err)
})
}
})
}
哦
今天又是流下没有技术的眼泪的一天?
哦
今天又是流下没有技术的眼泪的一天?
过分了昂
Promise.all()方法将多个Promise实例包装成一个Promise对象(p),接受一个数组(p1,p2,p3)作为参数,数组中不一定需要都是Promise对象,但是一定具有Iterator接口,如果不是的话,就会调用Promise.resolve将其转化为Promise对象之后再进行处理。
使用Promise.all()生成的Promise对象(p)的状态是由数组中的Promise对象(p1,p2,p3)决定的;
1、如果所有的Promise对象(p1,p2,p3)都变成fullfilled状态的话,生成的Promise对象(p)也会变成fullfilled状态,p1,p2,p3三个Promise对象产生的结果会组成一个数组返回给传递给p的回调函数;
2、如果p1,p2,p3中有一个Promise对象变为rejected状态的话,p也会变成rejected状态,第一个被rejected的对象的返回值会传递给p的回调函数。
Promise.all()方法生成的Promise对象也会有一个catch方法来捕获错误处理,但是如果数组中的Promise对象变成rejected状态时,并且这个对象还定义了catch的方法,那么rejected的对象会执行自己的catch方法,并且返回一个状态为fullfilled的Promise对象,Promise.all()生成的对象会接受这个Promise对象,不会返回rejected状态。
all(list) { return new Promise((resolve, reject) => { let resValues = []; let counts = 0; for (let [i, p] of list) { resolve(p).then(res => { counts++; resValues[i] = res; if (counts === list.length) { resolve(resValues) } }, err => { reject(err) }) } }) }
这么写的话是只要又一个promise失败, 整个.all 就失败了. 对业务是不是没那么友好
一、Promise概念
Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一。Promise.all()接受一个由promise任务组成的数组,可以同时处理多个promise任务,当所有的任务都执行完成时,Promise.all()返回resolve,但当有一个失败(reject),则返回失败的信息,即使其他promise执行成功,也会返回失败。和后台的事务类似。和rxjs中的forkJoin方法类似,合并多个 Observable 对象 ,等到所有的 Observable 都完成后,才一次性返回值。
二、Promise.all如何使用
对于 Promise.all(arr) 来说,在参数数组中所有元素都变为决定态后,然后才返回新的 promise。
// 以下 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)
})
三、Promise.all原理实现
function promiseAll(promises){
return new Promise(function(resolve,reject){
if(!Array.isArray(promises)){
return reject(new TypeError("argument must be anarray"))
}
var countNum=0;
var promiseNum=promises.length;
var 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)
}
})
}
var p1=Promise.resolve(1),
p2=Promise.resolve(2),
p3=Promise.resolve(3);
promiseAll([p1,p2,p3]).then(function(value){
console.log(value)
})四、Promise.all错误处理
有时候我们使用Promise.all()执行很多个网络请求,可能有一个请求出错,但我们并不希望其他的网络请求也返回reject,要错都错,这样显然是不合理的。如何做才能做到promise.all中即使一个promise程序reject,promise.all依然能把其他数据正确返回呢?
1、全部改为串行调用(失去了node 并发优势)
2、当promise捕获到error 的时候,代码吃掉这个异常,返回resolve,约定特殊格式表示这个调用成功了
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);
});Promise.all = function (promiseArrs) { //在Promise类上添加一个all方法,接受一个传进来的promise数组
return new Promise((resolve, reject) => { //返回一个新的Promise
let arr = []; //定义一个空数组存放结果
let i = 0;
function handleData(index, data) { //处理数据函数
arr[index] = data;
i++;
if (i === promiseArrs.length) { //当i等于传递的数组的长度时
resolve(arr); //执行resolve,并将结果放入
}
}
for (let i = 0; i < promiseArrs.length; i++) { //循环遍历数组
promiseArrs[i].then((data) => {
handleData(i, data); //将结果和索引传入handleData函数
}, reject)
}
})
}说all体验不好,那我们也可以自己做一个some方法,表示全部失败才算失败
Promise.some = function (promiseArrs) {
return new Promise((resolve, reject) => {
let arr = []; //定义一个空数组存放结果
let i = 0;
function handleErr(index, err) { //处理错误函数
arr[index] = err;
i++;
if (i === promiseArrs.length) { //当i等于传递的数组的长度时
reject(err); //执行reject,并将结果放入
}
}
for (let i = 0; i < promiseArrs.length; i++) { //循环遍历数组
promiseArrs[i].then(resolve, (e) => handleErr(i, e))
}
})
} var p11 = Promise.resolve(3).catch(function(err) {
return err;
});
var p22 = Promise.reject(2).catch(function(err) {
return err;
});
var p33 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, "foo");
}).catch(function(err) {
return err;
});
Promise.all([p11, p22, p33]).then(values => {
console.log(values); // [3, 2, "foo"]
}).catch(function(err) {
console.log(err); //不执行
});
借助楼上的代码,可以看出promise.a
ll虽然可以称为并发,依然是单线程的,和后端的并发实质性不一样.js的多线程并发可以借助cluster,各个子进程取到的结果统一返回给主进程进行管理,父子进程通讯机制与react父子组件通讯相似。
all(list) { return new Promise((resolve, reject) => { let resValues = []; let counts = 0; for (let [i, p] of list) { resolve(p).then(res => { counts++; resValues[i] = res; if (counts === list.length) { resolve(resValues) } }, err => { reject(err) }) } }) }
promise里面,形参resolve只执行一次的,你这里应该调用promise.resolve(p)来获取promise实例
function promiseAll(promises = []) {
let result = [];
function check(resolve) {
let length = result.length;
if (length === promises.length) {
resolve(result);
}
}
return new Promise(resolve => {
for (let i = 0; i < promises.length; i++) {
let promise = promises[i];
promise.then(res => {
result[i] = res;
check(resolve);
});
}
})
}
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('定时器1')
}, 3000)
});
let promise2 = new Promise(resolve => {
setTimeout(() => {
resolve('定时器2')
}, 2000);
})
promiseAll([promise2, promise1]).then(res => {
console.log(res)
})学习了
哦
今天又是流下没有技术的眼泪的一天?
哦
今天又是流下没有技术的眼泪的一天?
过分了昂
兄得长城是不是要哭倒了
all(list) { return new Promise((resolve, reject) => { let resValues = []; let counts = 0; for (let [i, p] of list) { resolve(p).then(res => { counts++; resValues[i] = res; if (counts === list.length) { resolve(resValues) } }, err => { reject(err) }) } }) }
resolve(p)这里有问题,因为p已经是一个Promise实例了,不需要resolve,状态发生改变(无论成功或失败)会自动进入then回调;如果此处resolve,会导致始终只能拿到一个promise的结果
function promiseAll(arr = []) {
return new Promise((resolve, reject) => {
const result = [],
len = arr.length;
arr.forEach(item => {
Promise.resolve(item).then(
res => {
result.push(res);
if (result.length === len) {
resolve(result);
}
},
err => {
reject(err);
}
);
});
});
}借鉴这两位兄台的代码: @irina9215 @luohong123
- Promise.all
Promise.all1 = function(list) {
return new Promise((resolve, reject) => {
let count = 0
let resArr = []
for (let i=0; i<list.length; i++) {
// Promise.resolve list 内部的非promise对象元素转成 promise 对象
let p = list[i].then ? list[i] : Promise.resolve(list[i])
p.then(res => {
count++
resArr[i] = res
if (count === list.length) {
resolve(resArr)
}
}).catch(err => {
reject(err)
})
}
})
}
- Promise.all 异常处理
// 原理:
// 当某一个请求失败时走进 reject 或者被 catch 捕获到了
// 可以创建一个新的 promise 手动调用 Promise.resolve(errMsg)
// 这样 Promise.all 就认为数组里的promise全部执行成功了
// 两种处理方法:
// 一种直接在每个子项Promise做catch处理并将错误结果return出来
// 另外一种对list做map处理为其每项假如 catch
var p1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('p1执行了...')
resolve('p1')
}, 1000)
})
// .catch(err => err) 此处直接 return err 相当于在链条上新 resolve(err),会在接下来的链条中体现
var p2 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('p2执行了...')
resolve('p2')
}, 2000)
})
// .catch(err => err)
var p3 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('p3执行了...')
reject('p3失败了,我是错误信息')
}, 100)
})
// .catch(err => err)
let list = [p1, p2, p3]
Promise.all(list.map(v => {
let p = v.then ? v : Promise.resolve(v) // 对不是promise的子项包装成promise
return p.catch(err => err)
}))
.then(res => console.log(res))
- 另外又简单的写了下
Promise.race的实现
Promise.race1 = function(list) {
return new Promise((resolve, reject) => {
for (let i=0; i<list.length; i++) {
let p = list[i].then ? list[i] : Promise.resolve(list[i])
p.then(res => resolve(res))
.catch(err => reject(err))
}
})
}
牛逼
Promise._all = function(list) {
let resValue = []
let count = 0
return new Promise((resolve, reject) => {
list.forEach((p, i) => {
p.then((res) => {
count++
resValue[i] = res
if(count === list.length) {
resolve(resValue)
}
}, err => {
reject(err)
})
})
})
}
var a = new Promise((resolve) => {
setTimeout(() => {
resolve(1000)
}, 1000)
})
var b = new Promise((resolve) => {
setTimeout(() => {
resolve(2000)
}, 1000)
})
Promise.all1([a, b]).then((c) => {
console.log(c)
})
Promise.all()的参数是传入一个数组,数组的值是Promise对象,这个函数返回一个Promise对象
这个函数顾名思义就是检查传入的所有数组是否都执行成功,如果都成功那么这个函数返回的Promise对象进入resolve状态并将所有promise成功的参数组成一个数组传给resolve函数,如果其中任何一个失败,那么就进入reject状态,并将第一个reject的promise的参数传给Promise.all返回的promise对象的reject函数
原理实现:
function promiseAll(promiseArr) {
return new Promise((resolve,reject) => {
let count = 0;
const result = []
for(let i = 0;i < promiseArr.length;i++){
promiseArr[i].then(res => {
count ++
result.push(res)
if(count == promiseArr.length) {
resolve(result)
}
},rej => reject(rej))
}
})
}
const pro1 = new Promise((res,rej) => {
setTimeout(() => {
res('1')
},1000)
})
const pro2 = new Promise((res,rej) => {
setTimeout(() => {
res('2')
},2000)
})
const pro3 = new Promise((res,rej) => {
setTimeout(() => {
res('3')
},3000)
})
const proAll = promiseAll([pro1,pro2,pro3]).then(res => console.log(res)).catch((e) => {
console.log(e)
})
哦
今天又是流下没有技术的眼泪的一天?
过分了昂
流下没有技术眼泪的第218天
说一下对处理异常方式的理解。const p = Promise.all([p1,p2])的特点是当参数数组中的promise实例p1、p2都返回resolved时p才会返回resloved,只要参数数组实例中有一个返回rejected时,p就会返回reject,另一个resolved的结果也没有被返回,所以这并不是我们想要的结果。怎么处理这种异常呢?
其实给数组中的promise实例定义了错误处理catch方法的时候,就不会在走p的catch的方法,且参数实例在执行完catch方法之后状态会变成resolved。
var p1 =new Promise(function(resolve,reject){
resolve(1);
})
.then(result => result)
.catch(e => e);
var p2 = new Promise(function(resolve,reject){
resolve(2);
})
.then(result => result)
.catch(e => e);
Promise.all([p1, p2])
.then(function (result) {
console.log(results);
})
.catch(e={
console.log(e);
});执行完catch方法后,也会变成resolved,导致Promise.all()方法参数里面的两个实例都会resolved,因此会调用then方法指定的回调函数,而不会调用catch方法指定的回调函数。
说all体验不好,那我们也可以自己做一个some方法,表示全部失败才算失败
Promise.some = function (promiseArrs) { return new Promise((resolve, reject) => { let arr = []; //定义一个空数组存放结果 let i = 0; function handleErr(index, err) { //处理错误函数 arr[index] = err; i++; if (i === promiseArrs.length) { //当i等于传递的数组的长度时 reject(err); //执行reject,并将结果放入 } } for (let i = 0; i < promiseArrs.length; i++) { //循环遍历数组 promiseArrs[i].then(resolve, (e) => handleErr(i, e)) } }) }
这段代码岂不是没有起到all的作用,只要有一个resolve, 就不会执行后面的promise了
function promiseAll(promises){
return new Promise(function(resolve,reject){
if(!Array.isArray(promises)){
return reject(new TypeError("argument must be anarray"))
}
var countNum=0;
var promiseNum=promises.length;
var resolvedvalue=new Array(promiseNum);
for(let i=0;i<promiseNum;i++){
Promise.resolve(promises[i]).then(function(value){
countNum += 1;
resolvedvalue[i] = value;
if(countNum === promiseNum){
resolve(resolvedvalue);
}
}).catch(function(value){
resolve(value);
})
}
})
}
let p1 = Promise.resolve(1);
let p2 = Promise.resolve(2);
let p3 = Promise.resolve(3);
let p4 = Promise.reject(4);
promiseAll([p1,p2,p3]).then(function(value){
console.log(value)
})
promiseAll([p1,p2,p4]).then(function(value){
console.log(value)
})
有问题欢迎指正!
all(list) { return new Promise((resolve, reject) => { let resValues = []; let counts = 0; for (let [i, p] of list) { resolve(p).then(res => { counts++; resValues[i] = res; if (counts === list.length) { resolve(resValues) } }, err => { reject(err) }) } }) }
resolve(p)这里有问题,因为p已经是一个Promise实例了,不需要resolve,状态发生改变(无论成功或失败)会自动进入then回调;如果此处resolve,会导致始终只能拿到一个promise的结果
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve
Promise.resolve(value)方法返回一个以给定值解析后的Promise 对象。如果这个值是一个 promise ,那么将返回这个 promise ; 他写的问题在没用 Promise.resolve
Promise.all 实现:
var promise1 = 41;
var promise2 = 42;
var promise3 = new Promise(function (resolve, reject) {
setTimeout(resolve, 5000, 'foo');
});
function p1(time) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(time);
}, time);
});
}
// Promise 扩展
Promise.all__fake = (promiseAry) => {
return new Promise((resolve, reject) => {
let resultAry = [],
index = 0;
for (let i = 0; i < promiseAry.length; i++) {
Promise.resolve(promiseAry[i])
.then((result) => {
index++;
resultAry[i] = result;
if (index === promiseAry.length) {
resolve(resultAry);
}
})
.catch((reason) => {
reject(reason);
});
}
});
};
Promise.all__fake([promise1, promise2, promise3]).then(function (values) {
console.log(values);
});
Promise.all__fake([p1(5000), p1(1000)]).then(function (res) {
console.log(res); //[5000,1000]
});Promise.all 错误处理:
使用 try catch,使 promise 不进入 reject 函数
const getVideoList = () => {
return new Promise((resolve, reject) => {
API.getHomeVideo({ agtId: this.data.agtId }).then((res) => {
try {
let result = res.data.data.slic(0, 6); // slice 书写错误
resolve({ swiperList: result });
} catch (error) {
resolve([]);
}
});
});
};Promise.every 扩展,所有的 promise 都错误才触发 reject,否则一律返回
Promise.every = (promiseAry) => {
// 所有的 promise 都错误才触发 reject
return new Promise((resolve, reject) => {
let resultAry = [],
errorAry = [],
index = 0,
index__error = 0;
for (let i = 0; i < promiseAry.length; i++) {
Promise.resolve(promiseAry[i])
.then((result) => {
index++;
resultAry[i] = result;
if (index === promiseAry.length) {
resolve(resultAry);
}
})
.catch((reason) => {
index__error++;
errorAry[i] = reason;
// 都有都错误
if (index__error === promiseAry.length) {
reject(errorAry);
}
if (index + index__error === promiseAry.length) {
resolve(resultAry);
}
});
}
});
};Promise.all 使用
场景1: p1、p3 是 Promise 实例;p2 是普通变量
p1 = new Promise((resolve, reject) => {
resolve('p1');
})
p2 = 'p2';
p3 = new Promise((resolve, reject) => {
resolve('p3');
})
p = Promise.all([p1, p2, p3]);
p.then((data) => {
console.log('data:', data);
}).catch((error) => {
console.log('error:', error);
})
// 输出结果: data: (3) ["p1", "p2", "p3"]场景2:p1、p2 resolve;p3 reject,没有单独进行catch处理
p1 = new Promise((resolve, reject) => {
resolve('p1');
})
p2 = new Promise((resolve, reject) => {
resolve('p2');
})
p3 = new Promise((resolve, reject) => {
reject('p3');
})
p = Promise.all([p1, p2, p3]);
p.then((data) => {
console.log('data:', data);
}).catch((error) => {
console.log('error:', error);
})
// 输出结果:error: p3场景3: p1、p2 resolve;p3 reject,catch 有处理
p1 = new Promise((resolve, reject) => {
resolve('p1');
})
p2 = new Promise((resolve, reject) => {
resolve('p2');
})
p3 = new Promise((resolve, reject) => {
reject('p3 error');
}).catch(() => {
return Promise.resolve('p3')
})
p = Promise.all([p1, p2, p3]);
p.then((data) => {
console.log('data:', data);
}).catch((error) => {
console.log('error:', error);
})
// 输出结果:data: (3) ["p1", "p2", "p3"]Promise.all 方法接受一个数组作为参数(可以不是数组,但必须具有 Iterator 接口),p1、p2、p3 都是 Promise 实例(如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例)。
Promise.all 原理实现
Promise.all = function (promises) {
return new Promise((resolve, reject) => {
let index = 0;
let result = [];
if (promises.length === 0) {
resolve(result);
} else {
function processValue(i, data) {
result[i] = data;
if (++index === promises.length) {
resolve(result);
}
}
for (let i = 0; i < promises.length; i++) {
// promises[i] 可能是普通值
Promise.resolve(promises[i]).then((data) => {
processValue(i, data);
}, (err) => {
reject(err);
return;
});
}
}
});
}Promise.all 原理错误处理
p1、p2、p3 都 resolve,会触发 p 的 then 方法,参数 data 是数组,每一项取值对应该 Promise 实例 resolve 的值。
当 p1、p2、p3 没有实现自己 catch 方法时, 其中一个 reject,会触发 p 的 catch 方法,参数 error 是参数列表中第一个 reject 出来的值。
当 p1、p2、p3 有实现自己 catch 方法时, 其中一个 reject,触发 p 的 then 方法还是 catch 方法,取决于 Promise 实例 reject 后对应的 catch 方法是如何处理的。
static all(arr) {
return new PromiseA((resolve, reject)=>{
let i = 0;
let ret = [];
while(arr.length) {
let tmp = arr.shift();
tmp.then((param)=>{
ret[i] = param;
i++
if (i == arr.length) {
resolve(ret);
}
},(err) => {
reject(err);
})
}
});
}all 是 Promise 的静态方法
static all (list) {
return new MyPromise((resolve, reject) => {
let values = []
let count = 0
for (let [i, p] of list.entries()) {
// 数组参数如果不是 Promise 实例,先调用 Promise.resolve, 静态方法 this指向类
this.resolve(p).then(res => {
values[i] = res
count++
// 所有状态都变成fulfilled时返回的 Promise状态就变成fulfilled
if (count === list.length) resolve(values)
}, err => {
// 有一个被rejected时返回的 Promise状态就变成rejected
reject(err)
})
}
})
}all(list) { return new Promise((resolve, reject) => { let resValues = []; let counts = 0; for (let [i, p] of list) { resolve(p).then(res => { counts++; resValues[i] = res; if (counts === list.length) { resolve(resValues) } }, err => { reject(err) }) } }) }
你这里直接resolve(p)不对吧
一、Promise概念
Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一。Promise.all()接受一个由promise任务组成的数组,可以同时处理多个promise任务,当所有的任务都执行完成时,Promise.all()返回resolve,但当有一个失败(reject),则返回失败的信息,即使其他promise执行成功,也会返回失败。和后台的事务类似。和rxjs中的forkJoin方法类似,合并多个 Observable 对象 ,等到所有的 Observable 都完成后,才一次性返回值。
二、Promise.all如何使用
对于 Promise.all(arr) 来说,在参数数组中所有元素都变为决定态后,然后才返回新的 promise。
// 以下 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) })三、Promise.all原理实现
function promiseAll(promises){ return new Promise(function(resolve,reject){ if(!Array.isArray(promises)){ return reject(new TypeError("argument must be anarray")) } var countNum=0; var promiseNum=promises.length; var 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) } }) } var p1=Promise.resolve(1), p2=Promise.resolve(2), p3=Promise.resolve(3); promiseAll([p1,p2,p3]).then(function(value){ console.log(value) })四、Promise.all错误处理
有时候我们使用Promise.all()执行很多个网络请求,可能有一个请求出错,但我们并不希望其他的网络请求也返回reject,要错都错,这样显然是不合理的。如何做才能做到promise.all中即使一个promise程序reject,promise.all依然能把其他数据正确返回呢?
1、全部改为串行调用(失去了node 并发优势)
2、当promise捕获到error 的时候,代码吃掉这个异常,返回resolve,约定特殊格式表示这个调用成功了
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); });
如果无论成功或失败都执行 resolve,可以用 Promise.allSettled
Tip: 1. Promise.all() 方法接收一个 promise 的 iterable 类型(注:Array,Map,Set 都属于 ES6 的 iterable 类型)的输入,并且只返回一个 Promise 实例, 那个输入的所有 promise 的 resolve 回调的结果是一个数组。这个 Promise 的 resolve 回调执行是在所有输入的 promise 的 resolve 回调都结束,或者输入的 iterable 里没有 promise 了的时候。它的 reject 回调执行是,只要任何一个输入的 promise 的 reject 回调执行或者输入不合法的 promise 就会立即抛出错误,并且 reject 的是第一个抛出的错误信息。
2. 输出结果按照 promise 顺序输出(很多人都忽略这点)
3. 数组如果不是promise实例,要转化成promise实例 (很多人都忽略这点)
Promise.myAll = function (promises) {
return new Promise((resolve, reject) => {
let promiseRes = [];
promises.forEach(async (pr, index) => {
if (!(pr instanceof Promise)) {
pr = pr;
}
try {
const temp = await pr;
promiseRes.splice(index, 0, temp);
// promiseRes.push(temp);
if (promiseRes.length === promises.length) {
resolve(promiseRes);
}
} catch (error) {
reject(error);
}
});
});
};
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, "foo");
});
// const pErr = new Promise((resolve, reject) => {
// reject("总是失败");
// });
Promise.myAll([promise1, promise2, promise3])
.then((values) => {
console.log(values);
})
.catch((err) => {
console.log("err", err);
});Promise.all(values),返回一个 promise 实例。如果迭代器中所有的 promise 参数状态都是 resolved, 则 promise 实例的状态为 resolved,其 PromiseValue 为每个参数的 PromiseValue 组成的数组;
如果参数中的 promise 有一个失败(rejected),此实例的状态为 rejected,其 PromiseValue 为是第一个失败 promise 的 PromiseValue
Promise.all = function(values) {
return new Promise((resolve, reject) => {
var result = []
var resolvedCount = 0
if (value.length == 0) {
resolve([])
return
}
for (let i = 0; i < values.length; i++) {
Promise.resolve(values[i]).then(val => {
result[i] = val
resolvedCount++
if (resolvedCount == values.length) {
resolve(result)
}
}, reason => {
reject(reason)
})
}
})
}let Promise_all = async (Promise_Arr = new Array()) => {
let results = [],
errors = null;
for (let i = 0; i < Promise_Arr.length; i++) {
if (Promise_Arr[i] instanceof Promise) {
Promise_Arr[i]
.then((v) => {
results.push(v);
})
.catch((err) => {
errors = err;
});
} else {
throw new Error("检测到非Promise的存在");
}
}
return new Promise(async (resolve, reject) => {
while (1) {
await new Promise((resolve) => setTimeout(resolve, 100));
if (errors != null) reject(errors);
if (results.length == Promise_Arr.length) {
resolve(results);
break;
}
}
});
};
Promise_all([
Promise.resolve(1),
Promise.resolve(2),
new Promise(async (resolve, reject) => {
await new Promise((resolve) => setTimeout(resolve, 3000));
resolve(3);
}),
Promise.reject(4),
])
.then((res) => {
console.log("Promise_all", res);
})
.catch((err) => {
console.log("Promise_all", err);
});
Promise.all([
Promise.resolve(1),
Promise.resolve(2),
new Promise(async (resolve, reject) => {
await new Promise((resolve) => setTimeout(resolve, 3000));
resolve(3);
}),
Promise.reject(4),
])
.then((res) => {
console.log("Promise.all", res);
})
.catch((err) => {
console.log("Promise.all", err);
});
Promise._all = function (promises) {
return new Promise((resolve, reject) => {
const result = [], resolved = 0
const length = promises.length
const addResult = (item, index) => {
result[index] = item
resolved++
if (resolved === length) {
resolve(result)
}
}
promises.forEach((promise, index) => {
if (typeof promise.then === 'function') {
// thenable
promise.then((item) => {
addResult(item, index)
}).catch(reject)
} else {
// 非promise类型直接透传
addResult(promise, index)
}
})
})
}Promise.all = function (fns) {
const res = [];
return new Promise((rs, rj) => {
fns.forEach((fn, n) => {
Promise.resolve(fn).then(r => {
res[n] = r; // 结果按顺序插入
if (n === res.length - 1) rs(res);
}, e => {
rj(e);
})
});
})
}继续留下眼泪,啊哈哈哈
static all<T extends Iterable<any>>(args: T) { //约定T从属于Iterable类型
return new MyPromise((resolve, reject) => {
const promise = Array.from(args); //将可迭代对象转化为数组
let index: number = 0;
let result: any[] = [];
const foo = function (pos: number, data: any) {
result[pos] = data;
// 所有的promise对象都为fulfilled则改变状态
if (++index === promise.length) {
resolve(result);
}
}
if (promise.length === 0) { //如果为空则直接改状态为fulfilled
resolve(result);
} else {
for (let i = 0; i < promise.length; i++) {
// 使用MyPromise包裹一层,将原始值转化为MyPromise
MyPromise.resolve(promise[i]).then(data => {
foo(i, data);
}, reason => {
reject(reason);
})
}
}
})
}
Promise.myAll = (promises) => {
const _promises = Array.isArray(_promises) ? _promises : [promises];
const result = [];
let fulfilledNum = 0;
return new Promise((resolve, reject) => {
if (_promises.length === 0) return resolve([])
_promises.forEach((promise, index) => {
Promise.resolve(promise).then((resp) => {
result[index] = resp;
fulfilledNum += 1;
if (result.length === _promises.length) {
resolve(result);
}
}, reject);
});
});
};Promise.fakeAll = function (promises) {
return new Promise((resolve, reject) => {
const result = [];
let count = 0;
promises.forEach((p, i) => {
p.then(
(data) => {
count++;
result[i] = data;
if (count === promises.length) {
resolve(result);
}
},
(e) => reject(e)
);
});
});
};
function createPromise(i) {
return Promise.resolve(i);
}
console.log(
Promise.fakeAll([createPromise(1), createPromise(2)]).then((data) => {
console.log(data);
})
);