实现Promise的first等各种变体

27次阅读

共计 4122 个字符,预计需要花费 11 分钟才能阅读完成。

原文地址:https://www.xiabingbao.com/po…
本篇文章主要是想通过 ES6 中 Promise 提供的几个方法,来实现诸如 first、last、none、any 等各种变体方法!
在标准的 ES6 规范中,提供了 Promise.all 和 Promise.race 两种,我们首先来了解下这两个方法是干嘛的,方便我们后面工作的展开。Promise.all 中所有的 Promise 实例都处于完成状态,该方法才进入完成状态,否则任意一个被拒绝,则该方法进入拒绝状态,并舍弃其他所有完成的结果,拒绝原因是第一个被拒绝的实例的原因。Promise.race 中任意的一个 Promise 实例变成完成状态或者拒绝状态,则 race 结束,race 的结果即为第一个变成最终状态的结果!更详细的可以参考下阮一峰的文章 Promise 对象之 Promise.all。
1. 准备工作
在开始编写各种变体方法之前,这里我们首先定义几个一会儿要使用的几个 Promise 实例:
/**
* 创建一个 Promise 对象的实例
* @param name {string} 该实例的名称
* @param flag {boolean} 返回的结果状态:完成还是拒绝
* @param diff {number} 延迟的时间
*/
var createPromiseCase = (name, flag, diff) => {
return new Promise(( resolve, reject) => {
setTimeout(() => {
flag ? resolve(name) : reject(new Error( ‘testPromise is error, name: ‘ + name) );
}, diff );
} );
};

var p1_suc_100 = createPromiseCase(‘p1-suc-100’, true, 100);
var p2_suc_500 = createPromiseCase(‘p2-suc-500’, true, 500);
var p3_suc_300 = createPromiseCase(‘p3-suc-300’, true, 300);
var p4_fail_400 = createPromiseCase(‘p4-fail-400’, false, 400);
var p5_fail_200 = createPromiseCase(‘p5-fail-200’, false, 200);
2. 各种变体方法
2.1 Promise.first
场景:一个页面当前正处于 loading 状态,同时请求了多个接口,无论哪个接口正确返回结果,则 loading 效果取消!或者其他的要获取获取第一个完成状态的值。
这里就要用到了 Promise.first 了,只要任意一个 Promise 实例变成完成状态,则 Promise.first 变成完成状态。其实这里并不适合 Promise.race 方法,因为第一个变成拒绝状态的实例也会激活 Promise.race,
if (!Promise.first) {
// get first resolve result
Promise.first = promiseList => {
return new Promise(( resolve, reject) => {
var num = 0;
var len = promiseList.length;
promiseList.forEach(pms => {
Promise.resolve(pms).then(resolve).catch(() => {
num++;
if (num === len) {
reject(‘all promises not resolve’);
}
} );
} );
} );
};
}
调用方式:
Promise.first([p4_fail_400, p2_suc_500, p3_suc_300])
.then(res => console.log(res)) // p3-suc-300
.catch(e => console.error(e))
可以看到每次获取的 p3_suc_300 的值,因为 p4 是失败的状态,p2 的完成状态没有 p3 快,因此这里获取到了 p3 的结果。
2.2 Promise.last
与 Promise.first 对应的则是 Promise.last,获取最后变成完成状态的值。这里与 Promise.first 不同的是,只有最后一个 Promise 都变成最终态(完成或拒绝),才能知道哪个是最后一个完成的,这里我采用了计数的方式,then 和 catch 只能二选一,等计数器达到 list.length 时,执行外部的 resolve。
if (!Promise.last) {
// get last resolve result
Promise.last = promiseList => {
return new Promise((resolve, reject) => {
let num = 0;
let len = promiseList.length;
let lastResolvedResult;

const fn = () => {
if (++num===len) {
lastResolvedResult ? resolve(lastResolvedResult) : reject(‘all promises rejected’);
}
}
promiseList.forEach(pms => {
Promise.resolve(pms)
.then(res => {
lastResolvedResult = res;
fn()
})
.catch(fn);
} )
} )
}
}
调用方式:
Promise.last([p1_suc_100, p2_suc_500, p5_fail_200, p3_suc_300, p4_fail_400])
.then(res => console.log(res)) // p2-suc-500
.catch(e => console.error(e))
p2 需要 500ms 才能完成,是最晚完成的。
2.3 Promise.none
Promise.none 与 Promise.all 正好相反,所有的 promise 都被拒绝了,则 Promise.none 变成完成状态。该方法可以用 Promise.first 来切换,当执行 Promise.first 的 catch 时,则执行 Promise.none 中的 resolve。不过这里我们使用 Promise.all 来实现。
if (!Promise.none) {
// if all the promises rejected, then succes
Promise.none = promiseList => {
return Promise.all(promiseList.map( pms => {
return new Promise(( resolve, reject) => {
// 将 pms 的 resolve 和 reject 反过来
return Promise.resolve(pms).then(reject, resolve);
} )
} ) )
}
}
调用方式:
Promise.none([p5_fail_200, p4_fail_400])
.then(res => console.log(res))
.catch(e => console.error(e))

// then 的输出结果:
// [
// Error: testPromise is error, name: p5-fail-200,
// Error: testPromise is error, name: p4-fail-400
// ]
两个 promise 都失败后,则 Promise.none 进入完成状态。
2.4 Promise.any
Promise.any 表示只获取所有的 promise 中进入完成状态的结果,被拒绝的则忽略掉。
if (!Promise.any) {
// get only resolve the results
Promise.any = promiseList => {
let result = [];
return Promise.all(promiseList.map( pms => {
return Promise.resolve(pms)
.then(res => result.push( res) )
.catch(e => {} );
} ) ).then(( res) => {
return new Promise(( resolve, reject) => {
result.length ? resolve(result) : reject();
} )
} )
}
}
调用方式:
Promise.any([p1_suc_100, p2_suc_500, p5_fail_200, p3_suc_300, p4_fail_400])
.then(res => console.log(res)) // [“p1-suc-100”, “p3-suc-300”, “p2-suc-500”]
.catch(e => console.error(e))
2.5 Promise.every
最后一个的实现比较简单,所有的 promise 都进入完成状态,则返回 true,否则返回 false。
if (!Promise.every) {
// get the boolean if all promises resolved
Promise.every = promiseList => {
return Promise.all(promiseList)
.then(() => Promise.resolve(true))
.catch(() => Promise.resolve(false));
}
}
调用方式:
Promise.every([p1_suc_100, p2_suc_500, p3_suc_300])
.then(result => console.log(‘Promise.every’, result)); // Promise.every true

Promise.every([p1_suc_100, p4_fail_400])
.then(result => console.log(‘Promise.every’, result)); // Promise.every false
3. 总结
Promise 还有各种方面的应用,很多类库也都实现了类似的方法,这里也仅仅是鄙人拙见,稍微实现了 Promise 的变体方法,加深下对 Promise 的理解。
原文地址:蚊子的博客

正文完
 0