实现Promise的first等各种变体
本篇文章主要是想通过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的理解。
实现Promise的first等各种变体的更多相关文章
- 自然语言19.1_Lemmatizing with NLTK(单词变体还原)
QQ:231469242 欢迎喜欢nltk朋友交流 https://www.pythonprogramming.net/lemmatizing-nltk-tutorial/?completed=/na ...
- 【Visual Lisp】变体与安全数组
(vlax-make-variant) ;;创建一个未初始化的变体 ;;01.整型值变体(setq myvar (vlax-make-variant 10)) ;;创建整型值变体,返回 #<va ...
- labview 变体数据类型
变体数据类型是LabVIEW中多种数据类型的容器.将其它数据转换为变体时,变体将存储数据和数据的原始类型,保证日后可将变体数据反向转换. 例如,如将字符串数据转换为变体,变体将存储字符串的文本,以及说 ...
- Bootstrap 标签的变体 实例样式
Bootstrap 标签样式,代码如下: <!DOCTYPE html> <html> <head> <title>Bootstrap 实例 - 标签的 ...
- Odoo / PS Cloud12版本中,产品变体功能如何使用
场景: 产品:陶瓷马克杯 产品颜色变体:红色.蓝色.白色 产品尺寸变体:10CM.12CM.15CM 每个变体都有不同价格维度 odoo / PS Cloud 专业实施开发 EMAIL:1715860 ...
- 二叉查找树及B-树、B+树、B*树变体
动态查找树主要有二叉查找树(Binary Search Tree),平衡二叉查找树(Balanced Binary Search Tree), 红黑树 (Red-Black Tree ), 都是典型的 ...
- (转) 干货 | 图解LSTM神经网络架构及其11种变体(附论文)
干货 | 图解LSTM神经网络架构及其11种变体(附论文) 2016-10-02 机器之心 选自FastML 作者:Zygmunt Z. 机器之心编译 参与:老红.李亚洲 就像雨季后非洲大草原许多野 ...
- 完全图解RNN、RNN变体、Seq2Seq、Attention机制
完全图解RNN.RNN变体.Seq2Seq.Attention机制 本文主要是利用图片的形式,详细地介绍了经典的RNN.RNN几个重要变体,以及Seq2Seq模型.Attention机制.希望这篇文章 ...
- Delphi 变体数组 Dataset Locate 查找定位
Format 函数 Delphi 支持“开参数”和动态数组,变体数组,使用时的语法类似 Delphi 中的集合:采用两个方括号把不同类型的变量括起来(这太方便了啊),也可以采用声明一个 TVarRec ...
随机推荐
- oracle入门(6)——PL/SQL常用语法
[本文介绍] 本文不是”语法大全“,只是记录下作项目里自己常用的一些语法.方便查询. [语法] [输出] (1)输出语法 DBMS_OUTPUT.PUT_LINE( ) [定义] (1)定义变 ...
- oracle中 rownum 与 connect by的结合使用
原文:http://blog.sina.com.cn/s/blog_a26966d90102wwkb.html oracle中 rownum 与 connect by的结合使用 SELECT ROWN ...
- VS安装程序制作之MSI/EXE
MSI文件是Windows Installer的数据包,它实际上是一个数据库,包含安装一种产品所需要的信息和在很多安装情形下安装(和卸载)程序所需的指令和数据.MSI文件将程序的组成文件与功能关联起来 ...
- C++入门(1)
#include<>直接从编译器自带的函数库中寻找文件 #include""是先从自定义的文件中找 ,如果找不到在从函数库中寻找文件 采用"< > ...
- abap 开发之创建表维护生成器
在sap开发中有时需要对一些自建表维护数据,但又不想写程序,怎么办呢??这个时候我们可以直接生成个表维护生成器,为其定义一个事物码就ok了.以下是表格维护生成器的生成步骤. 首先我们需要先定义表.输入 ...
- Spark2.0机器学习系列之9: 聚类(k-means,Bisecting k-means,Streaming k-means)
在Spark2.0版本中(不是基于RDD API的MLlib),共有四种聚类方法: (1)K-means (2)Latent Dirichlet allocation (LDA) ...
- 1141 PAT Ranking of Institutions[难]
1141 PAT Ranking of Institutions (25 分) After each PAT, the PAT Center will announce the ranking of ...
- TensorFlow学习笔记(七)TesnorFlow实现计算加速
目录: 一.TensorFlow使用GPU 二.深度学习训练与并行模式 三.多GPU并行 四.分布式TensorFlow 4.1分布式TensorFlow的原理 4.2分布式TensorFlow模型训 ...
- Nginx基本介绍
1.Nginx介绍 nginx是由俄罗斯人开发的一款高性能的http和反向代理服务器,也可以用来作为邮件代理.相比较于其他的服务器,具有占用内存少,稳定性高等优势 2.反向代理 正向代理类似一个跳板机 ...
- ACM-ICPC 2018 南京赛区网络预赛 - L Magical Girl Haze (分层迪杰斯特拉)
题意:N个点,M条带权有向边,求可以免费K条边权值的情况下,从点1到点N的最短路. 分析:K<=10,用dist[i][j]表示从源点出发到点i,免费j条边的最小花费.在迪杰斯特拉的dfs过程中 ...