前端JavaScript基础训练系列一百七十一:并发迭代

前端JavaScript基础训练系列一百七十一:并发迭代

有些时候会需要在一列 Promise 中迭代,并对所有 Promise 都执行某个任务,非常类似于 对同步数组可以做的那样(比如 forEach(…)、map(…)、some(…) 和 every(…))。如果 要对每个 Promise 执行的任务本身是同步的,那这些工具就可以工作,就像前面代码中的

在这个 first(…) 实现中,如它的所有 promise 都拒绝的话,它不会拒绝。 它只会挂住,非常类似于 Promise.race([])。如果需要的话,可以添加额 外的逻辑跟踪每个 promise 拒绝。如果所有的 promise 都被拒绝,就在主 promise 上调用 reject()。这个实现留给你当练习。

forEach(…)。

但如果这些任务从根本上是异步的,或者可以 / 应该并发执行,那你可以使用这些工具的异步版本,许多库中提供了这样的工具。

举例来说,让我们考虑一下一个异步的 map(…) 工具。它接收一个数组的值(可以是 Promise 或其他任何值),外加要在每个值上运行一个函数(任务)作为参数。map(…) 本 身返回一个 promise,其完成值是一个数组,该数组(保持映射顺序)保存任务执行之后 的异步完成值:

    if (!Promise.map) {
         Promise.map = function(vals,cb) {
// 一个等待所有map的promise的新promise return Promise.all(
// 注:一般数组map(..)把值数组转换为 promise数组 vals.map( function(val){
// 用val异步map之后决议的新promise替换val return new Promise( function(resolve){
                         cb( val, resolve );
} ); })
); };
}

在这个 map(…) 实现中,不能发送异步拒绝信号,但如果在映射的回调 (cb(…))内出现同步的异常或错误,主 Promise.map(…) 返回的 promise
就会拒绝。

下面展示如何在一组 Promise(而非简单的值)上使用 map(…):

    var p1 = Promise.resolve( 21 );
     var p2 = Promise.resolve( 42 );
     var p3 = Promise.reject( "Oops" );
// 把列表中的值加倍,即使是在Promise中 Promise.map( [p1,p2,p3], function(pr,done){
// 保证这一条本身是一个Promise Promise.resolve( pr )
.then(
// 提取值作为v function(v){
// map完成的v到新值
                 done( v * 2 );
             },
// 或者map到promise拒绝消息
done );
})
.then( function(vals){
         console.log( vals );         // [42,84,"Oops"]
     } );

Promise API 概述

本章已经在多处零零碎碎地展示了 ES6 Promise API,现在让我们来总结一下。

下面的 API 只对于 ES6 是原生的,但是有符合规范的适配版(不只是对 Promise 库的扩展),其定义了 Promise 及它的所有相关特性,这样你在前 ES6 浏览器中也可以使用原生 Promise。这样的适配版之一是 Native Promise Only(http://github.***/getify/native-promise-only),是我写的。

new Promise(…) 构造器

有启示性的构造器 Promise(…) 必须和 new 一起使用,并且必须提供一个函数回调。这个 回调是同步的或立即调用的。这个函数接受两个函数回调,用以支持 promise 的决议。通 常我们把这两个函数称为 resolve(…) 和 reject(…):

var p = new Promise( function(resolve,reject){ // resolve(..)用于决议/完成这个promise
// reject(..)用于拒绝这个promise
} );

reject(…) 就是拒绝这个 promise;但 resolve(…) 既可能完成 promise,也可能拒绝,要 根据传入参数而定。如果传给 resolve(…) 的是一个非 Promise、非 thenable 的立即值,这 个 promise 就会用这个值完成。

但是,如果传给 resolve(…) 的是一个真正的 Promise 或 thenable 值,这个值就会被递归展 开,并且(要构造的)promise 将取用其最终决议值或状态。

Promise.resolve(…) 和 Promise.reject(…)

创建一个已被拒绝的 Promise 的快捷方式是使用 Promise.reject(…),所以以下两个
promise 是等价的:

     var p1 = new Promise( function(resolve,reject){
         reject( "Oops" );
     } );
     var p2 = Promise.reject( "Oops" );
Promise.resolve(..) 常用于创建一个已完成的 Promise,使用方式与 Promise.reject(..)

类似。但是,Promise.resolve(…) 也会展开 thenable 值(前面已多次介绍)。在这种情况 下,返回的 Promise 采用传入的这个 thenable 的最终决议值,可能是完成,也可能是拒绝:

     var fulfilledTh = {
         then: function(cb) { cb( 42 ); }
     };
     var rejectedTh = {
         then: function(cb,errCb) {
             errCb( "Oops" );
} };
     var p1 = Promise.resolve( fulfilledTh );
     var p2 = Promise.resolve( rejectedTh );
// p1是完成的promise // p2是拒绝的promise

还要记住,如果传入的是真正的 Promise,Promise.resolve(…) 什么都不会做,只会直接 把这个值返回。所以,对你不了解属性的值调用 Promise.resolve(…),如果它恰好是一个 真正的 Promise,是不会有额外的开销的。

转载请说明出处内容投诉
CSS教程_站长资源网 » 前端JavaScript基础训练系列一百七十一:并发迭代

发表评论

欢迎 访客 发表评论

一个令你着迷的主题!

查看演示 官网购买