实现Promise.all、Promise.race、Promise.finally

1. 实现Promise.all

  • 实现思路
    promise.all(iterable)返回一个新的promise实例。此实例在iterable参数内所有的promisefulfilled或者参数中不包含promise时,状态才变成fulfilled;如果参数中有一个失败rejected,此实例回调失败,失败的信息是第一个失败promise的返回结果。
let p1 = new Promise(function (resolve, reject) {
  resolve(42);
})
let p2 = new Promise(function (resolve, reject) {
  resolve(43);
})
let p3 = new Promise(function (resolve, reject) {
  resolve(44);
})

let p4 = Promise.all([p1, p2, p3]);
p4.then(function (value) {
  console.log(value);    // [ 42, 43, 44 ]
})
let p1 = new Promise(function (resolve, reject) {
  resolve(42);
})
let p2 = new Promise(function (resolve, reject) {
  reject(43);
})
let p3 = new Promise(function (resolve, reject) {
  resolve(44);
})

let p4 = Promise.all([p1, p2, p3]);
p4.catch(function (value) {
  console.log(value);    // 43
})

所以总结promise.all的特点,即为:
如果传入的参数为空的可迭代对象,promise.all会同步地返回一个已完成状态的promise;如果传入的参数中不包含任何promisepromise.all会异步地返回一个已完成状态的promise;其他情况下,promise.all返回一个处理中(pending)状态的promise
promise.all的返回值是一个promise实例,如果传入的参数中的promise都变成完成状态,promise.all返回的promise异步地变成完成;如果传入的参数中有一个promise失败,promise.all将异步地见失败的结果给失败状态回调函数,而不管其他promise是否完成;并且在任何情况下,promise.all返回的promise的完成状态的结果都是一个数组。

  • promise.all代码实现
Promise.all_ = function(promises) {
    return new Promise((resolve, reject) => {
        // Array.from()可将可迭代对象转化为数组
        promises = Array.from(promises);
        if(promises.length===0) {
            resolve([]);
        } else {
            let result = [];
            let index = 0;
            for(let i=0; i<promises.length; i++) {
                // 考虑到promise[i]可能是thenable对象也可能是普通值
                Promise.resolve(promises[i]).then(data => {
                    result[i] = data;
                    if(++index===promises.length) {
                        // 所有的promise状态都是fulfilled,promise.all返回的实例才变成fulfilled状态
                        resolve(result);
                    }
                }, err => {
                    reject(err);
                    return;
                })
            }
        }
    })
}

2. 实现Promise.race

  • 实现思路
    Promise.race返回的仍然是一个Promise,它的状态与第一个完成的Promise的状态相同;如果传入的参数是不可迭代的,那么将会抛出错误。
let p1 = Promise.resolve(42);
let p2 = new Promise(function (resolve, reject) {
  reject(43);
})
let p3 = new Promise(function (resolve, reject) {
  resolve(44);
})

let p4 = Promise.race([p1, p2, p3]);
p4.then(function (value) {
  console.log(value);    // 42
})
  • Promise.race()实现
Promise.ra_ce = function(promises) {
    promises = Array.from(promises);
    return new Promise((resolve, reject) => {
        if(promises.length===0) {
            return;
        } else {
            for(let i=0; i<promises.length; i++) {
                Promise.resolve(promises[i]).then(data => {
                    resolve(data);
                    return;
                }, err => {
                    reject(err);
                    return;
                })
            }
        }
    })
}

3. 可迭代数据结构

Promsie.allPromise.race都只接受可迭代的数据结构,否则会报错,所以在不确定传入的promises是否为可迭代数据结构的情况下可以通过以下加以判断:

if(typeof promises[Symbol.iterator] !== 'function') {
    Promise.reject("args is not iteratable!");
}

ES6 规定,默认的 Iterator 接口部署在数据结构的 Symbol.iterator 属性,换个角度,也可以认为,一个数据结构只要具有 Symbol.iterator 属性(Symbol.iterator 方法对应的是遍历器生成函数,返回的是一个遍历器对象),那么就可以其认为是可迭代的。

  • 可迭代对象的特点
    具有 Symbol.iterator 属性,Symbol.iterator() 返回的是一个遍历器对象
    可以使用 for ... of 进行循环
    通过被 Array.from 转换为数组
    更多关于可迭代对象的实现参考博文https://blog.csdn.net/zl13015214442/article/details/90606961

3. 实现Promise.finally

不管成功还是失败,都会走到finally中,并且finally之后,还可以继续then。并且会将值原封不动的传递给后面的then

Promise.prototype.finally = function (callback) {
    return this.then((value) => {
        return Promise.resolve(callback()).then(() => {
            return value;
        });
    }, (err) => {
        return Promise.resolve(callback()).then(() => {
            throw err;
        });
    });
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值