您的位置:首页 > Web前端 > JavaScript

从零开始学_JavaScript_系列(50)——Promise(3)全部完成all和看谁最快race

2017-07-28 10:10 585 查看

7、全部完成才结束Promise.all

场景

我们在写ajax的时候,经常会面临这样一个场景:

我有三个ajax请求,但是需要等着三个ajax的请求结果都出来后再进行处理。

如果常见写法,我们需要在每个都执行完之后,依次判断一下其他的完成了没有,完成了才能继续,没完成就return。

但是使用
Promise.all
的话,问题简单多了。

Promise.all(iterable);

参数:

一般是一个数组,也可以是一个有迭代器接口的对象,但要求每个成员都是Promise实例。

返回值:

是一个Promise对象,为了方便称之为foo。

返回值的状态将维持pending不变,直到当参数的每个Promise实例的状态从pending变化为resolved,或者rejected时。

返回值Promise对象的变化规则:

1、参数的所有Promise都执行resolve,那么结果:

foo的状态resolved;

foo的then执行resolve;

foo的值是一个数组;

参数里的Promise对象的值按顺序(迭代器里的顺序,而非状态变化顺序)被放入到这个数组中,作为foo的值使用;

2、假如参数里的Promise对象有一个执行了reject,那么结果:

foo的状态rejected;

foo的then执行reject;

foo的值被执行了reject的那个Promise对象所决定;

foo的reject将在那个执行了reject的Promise对象执行后立刻执行(而不是等所有的都执行完毕);

3、假如参数中的Promise对象有多个执行了reject,那么结果:

同上一种情况的1、2和4

foo的值被第一个执行了reject的那个Promise对象所决定(后面的对其无影响);

情况一示例代码:

function delay(msg, time, isRej) {
return new Promise((res, rej) => {
setTimeout(() => {
isRej ? rej(msg) : res(msg)
}, time)
})
}

let promiseArray = [delay("first", 500), delay("second", 3000), delay("third", 1000)];

let foo = Promise.all(promiseArray);
foo.then(msg => {
console.log(msg)
}, err => {
console.log(err)
})

// ["first", "second", "third"] //3秒后


情况三示例代码(情况二可以参考情况三的,基本是一样的):

function delay(msg, time, isRej) {
return new Promise((res, rej) => {
setTimeout(() => {
isRej ? rej(msg) : res(msg)
}, time)
})
}

let promiseArray = [delay("first", 500), delay("second", 5500, true), delay("third", 1000, true)];

let foo = Promise.all(promiseArray);
foo.then(msg => {
console.log(msg)
}, err => {
console.log(err)
})

// third    //1秒后


另外由于Promise.all的返回值也是一个Promise实例,因此适用于Promise实例的方法,自然也适用于它。

关于参数,更复杂的情况

假如
Promise.all
的参数,不是一个单纯的
new Promise()
对象,而是
(new Promise()).then(() => {})
这样的,会发生什么事情呢?

首先,Promise.all执行哪个,不取决于第一个new Promise()里的状态,而是取决于
.then()
执行之后的状态。

原因在于,
(new Promise()).then(() => {})
这个表达式的值,是作为
Promise.all()
的参数的。

而这个表达式的值,取决于
.then()
的值,而这个值,和
new Promise()
并不是同一个Promise对象(参照本博客前几章)。

因此假如new Promise()执行了reject,而then里的reject执行了resolve,那么最终结果还是resolved,而不是rejected。

8、谁快用谁的Promise.race

Promise.race(iterable);

参数:

同Promise.all,懒得解释了。

返回值:

也是一个Promise对象,为了方便称之为foo。

返回值变化规律:

简单来说,参数的所有Promise对象,哪个的状态最先变化,返回值foo就使用它的。

例如:

参数里有三个Promise对象;

他们状态变化所需要时间分别是2秒,1秒,3秒;

他们的状态变化结果分别是resolved,resolved,rejected;

他们的值分别为’A’, ‘B’,’C’;

Promise.race执行,等1秒后,第二个Promise对象的状态变为resolved;

此时foo的状态立刻变为resolved,执行resolve,值为’B’;

另外两个的状态变化将不能影响foo;

如示例代码:

function delay(msg) {
let isFailed = Math.random() > 0.5;
let time = parseInt(Math.random() * 1000);
return new Promise((res, rej) => {
setTimeout(() => {
let data = {
msg,
time,
state: 'isFailed? ' + isFailed
}
isFailed ? rej(data) : res(data)
}, time)
})
}

let promiseArray = [delay("first"), delay("second"), delay("third")];

let foo = Promise.race(promiseArray);
foo.then(data => {
console.log(data.msg, data.time, data.state)
}, data => {
console.log(data.msg, data.time, data.state)
})

// 因为是随机结果,所以下面是随机结果之一
// second 207 isFailed? true


应用场景:

比如说你请求一个东西,但不想等待时间太久,比如说超过3秒钟就停止请求报告请求失败。

那么就可以使用这个,然后写一个Promise对象,3秒后执行reject的那种,作为最后一个参数。

然后只要超时,就自动执行,然后就ok了。

如示例:

function preventTimeout(promise) {
let timeout = new Promise((res, rej) => {
setTimeout(() => {
rej('超时了!')
}, 3000)
})
return Promise.race([promise, timeout])
}

let foo = new Promise((res, rej) => {
setTimeout(() => {
res("foo")
}, 4000);
})
let bar = preventTimeout(foo)
bar.then(null, val => {
console.log(val)
})

// 超时了! //3秒后


将需要进行超时检测的Promise对象,作为preventTimeout函数的参数,然后取用其返回值用于替代使用被检测的Promise对象。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐