原文地址: https://www.xiabingbao.com/po...javascript
本篇文章主要是想经过ES6中Promise提供的几个方法,来实现诸如first、last、none、any等各类变体方法!html
在标准的ES6规范中,提供了Promise.all
和Promise.race
两种,咱们首先来了解下这两个方法是干吗的,方便咱们后面工做的展开。Promise.all中全部的Promise实例都处于完成状态,该方法才进入完成状态,不然任意一个被拒绝,则该方法进入拒绝状态,并舍弃其余全部完成的结果,拒绝缘由是第一个被拒绝的实例的缘由。Promise.race中任意的一个Promise实例变成完成状态或者拒绝状态,则race结束,race的结果即为第一个变成最终状态的结果!更详细的能够参考下阮一峰的文章Promise对象之Promise.all。java
在开始编写各类变体方法以前,这里咱们首先定义几个一下子要使用的几个Promise实例:es6
/** * 建立一个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 );
场景:一个页面当前正处于loading状态,同时请求了多个接口,不管哪一个接口正确返回结果,则loading效果取消!或者其余的要获取获取第一个完成状态的值。promise
这里就要用到了Promise.first
了,只要任意一个Promise实例变成完成状态,则Promise.first变成完成状态。其实这里并不适合Promise.race
方法,由于第一个变成拒绝状态的实例也会激活Promise.race,post
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' ); } } ); } ); } ); }; }
调用方式:code
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的结果。htm
与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才能完成,是最晚完成的。
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进入完成状态。
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))
最后一个的实现比较简单,全部的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
Promise还有各类方面的应用,不少类库也都实现了相似的方法,这里也仅仅是鄙人拙见,稍微实现了Promise的变体方法,加深下对Promise的理解。
原文地址: 蚊子的博客