第 80 题:介绍下 Promise.all 使用、原理实现及错误处理

发布于 2022-11-09 16:00:05 字数 222 浏览 137 评论 37

const p = Promise.all([p1, p2, p3]);

Promise.all 方法接受一个数组作为参数,p1、p2、p3 都是 Promise 实例,如果不是,就会先调用下面讲到的 Promise.resolve 方法,将参数转为 Promise 实例,再进一步处理。(Promise.all 方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(37

舞袖。长 2022-05-04 13:56:07

借助楼上的代码,可以看出promise.a
ll虽然可以称为并发,依然是单线程的,和后端的并发实质性不一样.js的多线程并发可以借助cluster,各个子进程取到的结果统一返回给主进程进行管理,父子进程通讯机制与react父子组件通讯相似。

み青杉依旧ぃ 2022-05-04 13:56:07
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实例

作业与我同在 2022-05-04 13:56:07
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)
})
清君侧 2022-05-04 13:56:07

学习了

芸娘子的小脾气 2022-05-04 13:56:07

今天又是流下没有技术的眼泪的一天?

今天又是流下没有技术的眼泪的一天?

过分了昂

兄得长城是不是要哭倒了

梦毁影碎の 2022-05-04 13:56:07
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的结果

很快妥协 2022-05-04 13:56:07
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);
              }
            );
          });
        });
      }
仅此而已 2022-05-04 13:56:07

借鉴这两位兄台的代码: @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))
		}
	})
}
征棹 2022-05-04 13:56:07

牛逼

过期情话 2022-05-04 13:56:07

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)
})

孤独患者 2022-05-04 13:56:07

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)
})
儭儭莪哋寶赑 2022-05-04 13:56:07

今天又是流下没有技术的眼泪的一天?

过分了昂

流下没有技术眼泪的第218天

动次打次papapa 2022-05-04 13:56:07

说一下对处理异常方式的理解。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方法指定的回调函数。

寄居者 2022-05-04 13:56:07

说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了

木格〃 2022-05-04 13:56:07
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)
})

两个结果分别是:
Screen Shot 2020-03-06 at 3 24 56 AM

有问题欢迎指正!

好多鱼好多余 2022-05-04 13:56:07
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

心凉 2022-05-04 13:56:07

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);
          }
        });
    }
  });
};
国产ˉ祖宗 2022-05-04 13:56:07
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 方法是如何处理的。

看轻我的陪伴 2022-05-04 13:56:07
	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);
				})
			}
		});
	}
久隐师 2022-05-04 13:56:07

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)
        })
      }
    })
  }
碍人泪离人颜 2022-05-04 13:56:07
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)不对吧

┼──瘾|| 2022-05-04 13:56:07

一、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

打小就很酷 2022-05-04 13:56:07

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);
  });

更多

满栀 2022-05-04 13:56:07

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)
        })
      }
  })
}
演出会有结束 2022-05-04 13:56:07
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);
  });
昨迟人 2022-05-04 13:56:07
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)
            }
        })
    })
}
真心难拥有 2022-05-04 13:56:02
  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); //不执行
    });
素衣风尘叹 2022-05-04 13:55:40

说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))
      }
  })
}
梦幻的心爱 2022-05-04 13:52:40
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)
        }
    })
}
素罗衫 2022-05-04 13:50:55

一、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);
});
很酷不放纵 2022-05-04 13:48:29
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 就失败了. 对业务是不是没那么友好

蓝眸 2022-05-04 13:35:04
清音悠歌 2022-05-04 13:18:23

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状态。

-脸赞〃 2022-05-04 12:49:27

今天又是流下没有技术的眼泪的一天?

过分了昂

南薇 2022-05-04 12:13:16

今天又是流下没有技术的眼泪的一天?

无风消散 2022-05-03 21:42:13
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)
                })
            }
        })
    }
£烟消云散 2022-05-03 16:24:35

~没有更多了~

关于作者

0 文章
0 评论
23 人气
更多

推荐作者

lorenzathorton8

文章 0 评论 0

Zero

文章 0 评论 0

萧瑟寒风

文章 0 评论 0

mylayout

文章 0 评论 0

tkewei

文章 0 评论 0

17818769742

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文