欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

实现Promise的first等各种变体-蚊子的博客-SegmentFault思否

程序员文章站 2022-04-02 14:25:47
原文地址: https://www.xiabingbao.com/po... 本篇文章主要是想通过es6中promise提供的几个方法,来实现诸如first、last、none、...

原文地址: 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的理解。

原文地址: 蚊子的博客