8288分类目录 8288分类目录 8288分类目录
  当前位置:海洋目录网 » 站长资讯 » 站长资讯 » 文章详细 订阅RssFeed

实现Promise的first等各种变体

来源:本站原创 浏览:39次 时间:2023-04-20
实现Promise的first等各种变体

小蚊子

高级前端工程师
正文地址:蚊子的博客

实现Promise的first等各种变体-蚊子-前端博客

www.xiabingbao.com
本篇文章主要是想通过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 truePromise.every([p1_suc_100, p4_fail_400])    .then(result => console.log('Promise.every', result)); // Promise.every false
3. 总结

Promise还有各种方面的应用,很多类库也都实现了类似的方法,这里也仅仅是鄙人拙见,稍微实现了Promise的变体方法,加深下对Promise的理解。

  推荐站点

  • At-lib分类目录At-lib分类目录

    At-lib网站分类目录汇集全国所有高质量网站,是中国权威的中文网站分类目录,给站长提供免费网址目录提交收录和推荐最新最全的优秀网站大全是名站导航之家

    www.at-lib.cn
  • 中国链接目录中国链接目录

    中国链接目录简称链接目录,是收录优秀网站和淘宝网店的网站分类目录,为您提供优质的网址导航服务,也是网店进行收录推广,站长免费推广网站、加快百度收录、增加友情链接和网站外链的平台。

    www.cnlink.org
  • 35目录网35目录网

    35目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向35目录推荐、提交优秀网站。

    www.35mulu.com
  • 就要爱网站目录就要爱网站目录

    就要爱网站目录,按主题和类别列出网站。所有提交的网站都经过人工审查,确保质量和无垃圾邮件的结果。

    www.912219.com
  • 伍佰目录伍佰目录

    伍佰网站目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向伍佰目录推荐、提交优秀网站。

    www.wbwb.net