实现Promise的first等各种变体

更新日期: 2019-04-10阅读: 1.9k标签: promise

本篇文章主要是想通过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的理解。


原文地址: 蚊子的博客


链接: https://www.fly63.com/article/detial/2804

你真的了解 Promise 吗?Promise 必知必会(十道题)

Promise 想必大家十分熟悉,想想就那么几个 api,可是你真的了解 Promise 吗?本文根据 Promise 的一些知识点总结了十道题,看看你能做对几道。

剖析Promise内部结构,一步一步实现一个完整的、能通过所有Test case的Promise类

本文写给有一定Promise使用经验的人,如果你还没有使用过Promise,这篇文章可能不适合你,Promise标准中仅指定了Promise对象的then方法的行为,其它一切我们常见的方法/函数都并没有指定.

Async/Await替代Promise的6个理由

Async/Await替代Promise的6个理由:Async/Await是近年来JavaScript添加的最革命性的的特性之一。它会让你发现Promise的语法有多糟糕,而且提供了一个直观的替代方法。

Promise 原理解析与实现(遵循Promise/A+规范)

Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一,Promise 是一个构造函数, new Promise 返回一个 promise对象 接收一个excutor执行函数作为参数

简单模仿实现 Promise 的异步模式

这篇文章是考虑如何自己实现一个简单 Promise,用以理解 Promise。和原生 Promise的调用方法一样,支持链式调用,本文实现的方法只能用于参考Promise的原理,还有很多特性没有实现,比如 race,all 方法的实现。

数组的遍历你都会用了,那Promise版本的呢

在对数组进行一些遍历操作时,发现有些遍历方法对Promise的反馈并不是我们想要的结果。async/await为Promise的语法糖,文中会直接使用async/await替换Promise;map可以说是对Promise最友好的一个函数了,

Promise使用时应注意的问题

最近在使用axios库时遇到了个问题,后端接口报了500错误,但前端并未捕获到。在axios整体配置的代码中,过滤http code时,调用了filter401()、filter500(),但是这里注意并未将两个filter函数的结果返回,也就是并未返回promise,这就是导致问题出现的原因

es6 Promise 的基础用法

想必接触过Node的人都知道,Node是以异步(Async)回调著称的,其异步性提高了程序的执行效率,但同时也减少了程序的可读性。如果我们有几个异步操作,并且后一个操作需要前一个操作返回的数据才能执行

关于 Promise 的 9 个提示

你可以在 .then 里面 return 一个 Promise,每次执行 .then 的时候都会自动创建一个新的 Promise,对调用者来说,Promise 的 resolved/rejected 状态是唯一的,Promise 构造函数不是解决方案,使用 Promise.resolve

手写一款符合Promise/A+规范的Promise

Promise的一些用法在此不多赘述,本篇主要带领你手写一个Promise源码,学完你就会发现:Promise没有你想象中的那么难.本篇大概分为以下步骤:实现简单的同步Promise、增加异步功能、增加链式调用then、增加catch finally方法、增加all race 等方法、实现一个promise的延迟对象defer、最终测试

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!