-
Notifications
You must be signed in to change notification settings - Fork 3.3k
第 80 题:介绍下 Promise.all 使用、原理实现及错误处理 #130
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
哦 |
|
今天又是流下没有技术的眼泪的一天? |
过分了昂 |
Promise.all()方法将多个Promise实例包装成一个Promise对象(p),接受一个数组(p1,p2,p3)作为参数,数组中不一定需要都是Promise对象,但是一定具有Iterator接口,如果不是的话,就会调用Promise.resolve将其转化为Promise对象之后再进行处理。 |
这么写的话是只要又一个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。
三、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))
}
})
} |
|
借助楼上的代码,可以看出promise.a |
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)
}) |
学习了 |
兄得长城是不是要哭倒了 |
|
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 = function(list) {
} var a = new Promise((resolve) => { var b = new Promise((resolve) => { Promise.all1([a, b]).then((c) => { |
Promise.all()的参数是传入一个数组,数组的值是Promise对象,这个函数返回一个Promise对象 原理实现:
|
流下没有技术眼泪的第218天 |
说一下对处理异常方式的理解。const p = Promise.all([p1,p2])的特点是当参数数组中的promise实例p1、p2都返回resolved时p才会返回resloved,只要参数数组实例中有一个返回rejected时,p就会返回reject,另一个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的作用,只要有一个resolve, 就不会执行后面的promise了 |
有问题欢迎指正! |
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/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 错误处理:使用 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 = (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)
})
}
})
} |
你这里直接resolve(p)不对吧 |
如果无论成功或失败都执行 resolve,可以用 |
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.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);
})
});
})
} |
继续留下眼泪,啊哈哈哈 |
|
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);
})
); |
Uh oh!
There was an error while loading. Please reload this page.
Promise.all方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。(Promise.all方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。)
The text was updated successfully, but these errors were encountered: