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

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

场景

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

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

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

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

Promise.all(iterable);

参数:

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

返回值:

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

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

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

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

  1. foo的状态resolved;
  2. foo的then执行resolve;
  3. foo的值是一个数组;
  4. 参数里的Promise对象的值按顺序(迭代器里的顺序,而非状态变化顺序)被放入到这个数组中,作为foo的值使用;

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

  1. foo的状态rejected;
  2. foo的then执行reject;
  3. foo的值被执行了reject的那个Promise对象所决定;
  4. foo的reject将在那个执行了reject的Promise对象执行后立刻执行(而不是等所有的都执行完毕);

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

  1. 同上一种情况的1、2和4
  2. 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就使用它的。

例如:

  1. 参数里有三个Promise对象;
  2. 他们状态变化所需要时间分别是2秒,1秒,3秒;
  3. 他们的状态变化结果分别是resolved,resolved,rejected;
  4. 他们的值分别为’A’, ‘B’,’C’;
  5. Promise.race执行,等1秒后,第二个Promise对象的状态变为resolved;
  6. 此时foo的状态立刻变为resolved,执行resolve,值为’B’;
  7. 另外两个的状态变化将不能影响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对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值