Promise (一)含义 Promise 是异步编程的一种解决方案,比传统的解决方案(回调函数和事件)更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了 Promise
对象。Promise
可以说是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
Promise
对象有以下两个特点。
对象的状态不受外界影响。Promise
对象代表一个异步操作,有三种状态:pending
(进行中)、fulfilled
(已成功)和 rejected
(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是 Promise
这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise
对象的状态改变,只有两种可能:从 pending
变为 fulfilled
和从 pending
变为 rejected
。只要这两种情况发生,状态就不会再变,这时就称为 resolved(已定型)。如果改变已经发生了,你再对 Promise
对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。 注意,为了行文方便,本章后面的 resolved
统一只指 fulfilled
状态,不包含 rejected
状态。
有了 Promise
对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise
对象提供统一的接口,使得控制异步操作更加容易。
Promise
也有如下一些缺点。
Promise
一旦创建就会立即执行,无法中途取消。如果不设置回调函数,Promise
内部抛出的错误不会反应到外部。 当处于 pending
状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。 如果某些事件不断地反复发生,一般来说,使用 Stream 模式是比部署 Promise
更好的选择。
(二)用法 ES6 规定,Promise
对象是一个构造函数,用来生成 Promise
实例。
1 2 3 4 5 6 7 8 const promise = new Promise (function (resolve, reject ) { if (){ resolve(value); } else { reject(error); } });
Promise
构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve
和 reject
。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。
resolve
函数的作用是,将 Promise
对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果作为参数传递出去;reject
函数的作用是,将 Promise
对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误作为参数传递出去。
Promise
实例生成以后,可以用 then
方法分别指定 resolved
状态和 rejected
状态的回调函数。
1 2 3 4 5 promise.then(function (value ) { }, function (error ) { });
then
方法可以接受两个回调函数作为参数。第一个回调函数是 Promise
对象的状态变为 resolved
时调用,第二个回调函数是 Promise
对象的状态变为 rejected
时调用。这两个函数都是可选的,不一定要提供。它们都接受 Promise
对象传出的值作为参数。
下面是一个 Promise
对象的简单例子:timeout
方法返回一个 Promise
实例,表示一段时间以后才会发生的结果。过了指定的时间(ms
参数)以后,Promise
实例的状态变为 resolved
,就会触发then
方法绑定的回调函数。
1 2 3 4 5 6 7 8 9 function timeout (ms ) { return new Promise ((resolve, reject ) => { setTimeout (resolve, ms, 'done' ); }); } timeout(100 ).then((value ) => { console .log(value); });
下面是异步加载图片的例子。
1 2 3 4 5 6 7 8 9 10 11 12 function loadImageAsync (url ) { return new Promise (function (resolve, reject ) { const image = new Image(); image.onload = function ( ) { resolve(image); }; image.onerror = function ( ) { reject(new Error ('Could not load image at ' + url)); }; image.src = url; }); }
上面代码中,使用 Promise
包装了一个图片加载的异步操作。如果加载成功,就调用 resolve
方法,否则就调用 reject
方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 const getJSON = function (url ) { const promise = new Promise (function (resolve, reject ) { const handler = function ( ) { if (this .readyState !== 4 ) { return ; } if (this .status === 200 ) { resolve(this .response); } else { reject(new Error (this .statusText)); } }; const client = new XMLHttpRequest(); client.open("GET" , url); client.onreadystatechange = handler; client.responseType = "json" ; client.setRequestHeader("Accept" , "application/json" ); client.send(); }); return promise; }; getJSON("/posts.json" ).then(function (json ) { console .log('Contents: ' + json); }, function (error ) { console .error('出错了' , error); });
上面代码中,getJSON
是对 XMLHttpRequest
对象的封装,用于发出一个针对 JSON 数据的 HTTP 请求,并且返回一个 Promise
对象。需要注意的是,在 getJSON
内部,resolve
函数和 reject
函数调用时,都带有参数。
如果调用 resolve
函数和 reject
函数时带有参数,那么它们的参数会被传递给回调函数。reject
函数的参数通常是 Error
对象的实例,表示抛出的错误;resolve
函数的参数除了正常的值以外,还可能是另一个 Promise 实例,比如像下面这样。
1 2 3 4 5 6 7 8 const p1 = new Promise (function (resolve, reject ) { }); const p2 = new Promise (function (resolve, reject ) { resolve(p1); })
上面代码中,p1
和 p2
都是 Promise 的实例,但是 p2
的 resolve
方法将 p1
作为参数,即一个异步操作的结果是返回另一个异步操作。注意,这时 p1
的状态就会传递给 p2
,也就是说,p1
的状态决定了 p2
的状态。如果 p1
的状态是 pending
,那么 p2
的回调函数就会等待 p1
的状态改变;如果 p1
的状态已经是 resolved
或者 rejected
,那么 p2
的回调函数将会立刻执行。
1 2 3 4 5 6 7 8 9 10 11 12 const p1 = new Promise (function (resolve, reject ) { setTimeout (() => reject(new Error ('fail' )), 3000 ) }) const p2 = new Promise (function (resolve, reject ) { setTimeout (() => resolve(p1), 1000 ) }) p2 .then(result => console .log(result)) .catch(error => console .log(error))
上面代码中,p1
是一个 Promise,3 秒之后变为 rejected
。p2
的状态在 1 秒之后改变,resolve
方法返回的是 p1
。由于p2
返回的是另一个 Promise,导致p2
自己的状态无效了,由p1
的状态决定p2
的状态。所以,后面的 then
语句都变成针对后者(p1
)。又过了 2 秒,p1
变为 rejected
,导致触发 catch
方法指定的回调函数。
(三)特性 1. 立即执行性 1 2 3 4 5 6 7 8 9 10 var p = new Promise (function (resolve, reject ) { console .log("create a promise" ); resolve("success" ); }); console .log("after new Promise" );p.then(function (value ) { console .log(value); });
控制台输出:
1 2 3 "create a promise" "after new Promise" "success"
Promise 对象表示未来某个将要发生的事件,但在开始创建 Promise 时,作为参数传入的函数是会被立即执行的,只是其中执行的代码可以是异步代码。有人错以为只有当 Promise 对象调用 then
方法时,Promise 接收的函数才会执行。then
方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行。
注意,调用 resolve
或 reject
并不会终结 Promise 的参数函数的执行。
1 2 3 4 5 6 7 8 new Promise ((resolve, reject ) => { resolve(1 ); console .log(2 ); }).then(r => { console .log(r); });
上面代码中,调用 resolve(1)
以后,后面的 console.log(2)
还是会执行,并且会首先打印出来。这是因为立即 resolved 的 Promise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。
一般来说,调用 resolve
或 reject
后,Promise 的使命就完成了,后继操作应该放到 then
方法里面,而不应该直接写在 resolve
或 reject
的后面。所以,最好在它们前面加上 return
语句,这样就不会有意外。
1 2 3 4 5 new Promise ((resolve, reject ) => { return resolve(1 ); console .log(2 ); })
2. 三种状态 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 var p1 = new Promise (function (resolve, reject ) { resolve(1 ); }); var p2 = new Promise (function (resolve, reject ) { setTimeout (function ( ) { resolve(2 ); }, 500 ); }); var p3 = new Promise (function (resolve, reject ) { setTimeout (function ( ) { reject(3 ); }, 500 ); }); console .log(p1);console .log(p2);console .log(p3);setTimeout (function ( ) { console .log(p2); }, 1000 ); setTimeout (function ( ) { console .log(p3); }, 1000 ); p1.then(function (value ) { console .log(value); }); p2.then(function (value ) { console .log(value); }); p3.catch(function (err ) { console .log(err); });
控制台输出:
1 2 3 4 5 6 7 8 Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 1} Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined} Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined} 1 2 3 Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 2} Promise {[[PromiseStatus]]: "rejected", [[PromiseValue]]: 3}
Promise 的内部实现是一个状态机,它有三种状态:pending,resolved,rejected。当 Promise 刚创建完成时,处于 pending 状态;当 Promise 中的函数参数执行了 resolve()
后,Promise 由 pending 状态变成 resolved 状态;执行 reject()
则会由 pending 状态变成 rejected 状态。
p2、p3 刚创建完成时,控制台输出的这两台 Promise 都处于 pending 状态,但为什么 p1 是 resolved 状态呢?这是因为 p1 的函数参数中执行的是一段同步代码,Promise 刚创建完成,resolve 方法就已经被调用了,因而紧跟着的输出显示 p1 是 resolved 状态。我们通过两个 setTimeout
函数,延迟 1s 后再次输出 p2、p3 的状态,此时 p2、p3 已经执行完成,状态分别变成 resolved 和 rejected。
3. 状态不可逆性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 var p1 = new Promise (function (resolve, reject ) { resolve("success1" ); resolve("success2" ); }); var p2 = new Promise (function (resolve, reject ) { resolve("success" ); reject("reject" ); }); p1.then(function (value ) { console .log(value); }); p2.then(function (value ) { console .log(value); });
控制台输出:
Promise 状态一旦变成 resolved 或 rejected 时,Promise 的状态和值就固定下来了,不论后续再怎么调用 resolve 或 reject 方法,都不能改变它的状态和值。因此,p1 中 resolve("success2")
并不能将 p1 的值更改为 success2
,p2 中 reject("reject")
也不能将 p2 的状态由 resolved 改变为 rejected。
4. 链式调用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 var p = new Promise (function (resolve, reject ) { resolve(1 ); }); p.then(function (value ) { console .log(value); return value*2 ; }).then(function (value ) { console .log(value); }).then(function (value ) { console .log(value); return Promise .resolve('resolve' ); }).then(function (value ) { console .log(value); return Promise .reject('reject' ); }).then(function (value ) { console .log('resolve: ' + value); }, function (err ) { console .log('reject: ' + err); })
控制台输出:
1 2 3 4 5 1 2 undefined "resolve" "reject: reject"
Promise 对象的 then 方法返回一个新的 Promise 对象,因此可以链式调用 then 方法。then 方法接收两个函数作为参数,第一个参数是 Promise 执行成功时的回调,第二个参数是 Promise 执行失败时的回调。两个函数只会有一个被调用,函数的返回值将被用作创建 then 返回的 Promise 对象。这两个参数的返回值可以是以下三种情况中的一种:
return
一个同步的值,或者没有返回一个有效值时(默认返回 undefined),then
方法将返回一个 resolved 状态的 Promise 对象,Promise 对象的值就是这个返回值。return
另一个 Promise,then
方法将根据这个 Promise 的状态和值创建一个新的 Promise 对象返回。throw
一个同步异常,then
方法将返回一个 rejected 状态的 Promise, 值是该异常。根据以上分析,代码中第一个 then
会返回一个值为 2(1*2),状态为 resolved 的 Promise 对象,于是第二个 then
输出的值是 2。第二个 then
中没有返回值,因此将返回默认的 undefined,于是在第三个 then
中输出 undefined。第三个 then
和第四个 then
中分别返回一个状态是 resolved 的 Promise 和一个状态是 rejected 的 Promise,依次由第四个 then
中成功的回调函数和第五个 then
中失败的回调函数处理。
5. 回调异步性 1 2 3 4 5 6 7 8 9 var p = new Promise (function (resolve, reject ) { resolve("success" ); }); p.then(function (value ) { console .log(value); }); console .log("which one is called first ?" );
控制台输出:
1 2 "which one is called first ?" "success"
Promise 接收的函数参数是同步执行的,但 then
方法中的回调函数执行则是异步的,因此,”success” 会在后面输出。
6. 异常处理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 var p1 = new Promise (function (resolve, reject ) { foo.bar(); resolve(1 ); }); p1.then( function (value ) { console .log('p1 then value: ' + value); }, function (err ) { console .log('p1 then err: ' + err); } ).then( function (value ) { console .log('p1 then then value: ' +value); }, function (err ) { console .log('p1 then then err: ' + err); } ); var p2 = new Promise (function (resolve,reject ) { resolve(2 ); }); p2.then( function (value ) { console .log('p2 then value: ' + value); foo.bar(); }, function (err ) { console .log('p2 then err: ' + err); } ).then( function (value ) { console .log('p2 then then value: ' + value); }, function (err ) { console .log('p2 then then err: ' + err); return 1 ; } ).then( function (value ) { console .log('p2 then then then value: ' + value); }, function (err ) { console .log('p2 then then then err: ' + err); } );
控制台输出:
1 2 3 4 5 p1 then err: ReferenceError: foo is not defined p2 then value: 2 p1 then then value: undefined p2 then then err: ReferenceError: foo is not defined p2 then then then value: 1
Promise 中的异常由 then
参数中第二个回调函数处理,异常信息将作为 Promise 的值。异常一旦得到处理,then
返回的后续 Promise 对象将恢复正常,并会被 Promise 执行成功的回调函数处理。另外,需要注意 p1、p2 多级 then
的回调函数是交替执行的,这正是由 then
回调的异步性决定的。
7. Promise.resolve()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 var p1 = Promise .resolve(1 );var p2 = Promise .resolve(p1);var p3 = new Promise (function (resolve, reject ) { resolve(1 ); }); var p4 = new Promise (function (resolve, reject ) { resolve(p1); }); console .log(p1 === p2); console .log(p1 === p3);console .log(p1 === p4);console .log(p3 === p4);p4.then(function (value ) { console .log('p4=' + value); }); p2.then(function (value ) { console .log('p2=' + value); }) p1.then(function (value ) { console .log('p1=' + value); })
控制台输出:
1 2 3 4 5 6 7 true false false false p2=1 p1=1 p4=1
Promise.resolve(...)
可以接收一个值或者是一个 Promise 对象作为参数。当参数是普通值时,它返回一个 resolved 状态的 Promise 对象,对象的值就是这个参数;当参数是一个 Promise 对象时,它直接返回这个 Promise 参数。因此,p1 === p2。但通过 new 的方式创建的 Promise 对象都是一个新的对象,因此后面的三个比较结果都是 false。另外,为什么 p4 的 then
最先调用,但在控制台上是最后输出结果的呢?因为 p4 的 resolve
中接收的参数是一个 Promise 对象 p1,resolve
会对 p1 拆箱,获取 p1 的状态和值,但这个过程是异步的,可参考下一节。
8. resolve VS reject 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 var p1 = new Promise (function (resolve, reject ) { resolve(Promise .resolve('resolve' )); }); var p2 = new Promise (function (resolve, reject ) { resolve(Promise .reject('reject' )); }); var p3 = new Promise (function (resolve, reject ) { reject(Promise .resolve('resolve' )); }); p1.then( function fulfilled (value ) { console .log('fulfilled: ' + value); }, function rejected (err ) { console .log('rejected: ' + err); } ); p2.then( function fulfilled (value ) { console .log('fulfilled: ' + value); }, function rejected (err ) { console .log('rejected: ' + err); } ); p3.then( function fulfilled (value ) { console .log('fulfilled: ' + value); }, function rejected (err ) { console .log('rejected: ' + err); } );
控制台输出:
1 2 3 p3 rejected: [object Promise] p1 fulfilled: resolve p2 rejected: reject
Promise 回调函数中的第一个参数 resolve
,会对 Promise 执行拆箱动作。即当 resolve
的参数是一个 Promise 对象时,resolve
会拆箱获取这个 Promise 对象的状态和值,但这个过程是异步的。p1 拆箱后,获取到 Promise 对象的状态是 resolved,因此 fulfilled
回调被执行;p2 拆箱后,获取到 Promise 对象的状态是 rejected,因此 rejected
回调被执行。
但 Promise 回调函数中的第二个参数 reject
不具备拆箱的能力,reject 的参数会直接传递给 then
方法中的 rejected
回调。因此,即使 p3 reject
接收了一个 resolved 状态的 Promise,then
方法中被调用的依然是 rejected
,并且参数就是 reject
接收到的 Promise 对象。
(四)Promise 实现 实现 Promise 需要完全读懂 Promise A+ 规范 ,不过从总体的实现上看,有如下几个点需要考虑到:
then 需要支持链式调用,所以得返回一个新的 Promise; 处理异步问题,所以得先用 onResolvedCallbacks 和 onRejectedCallbacks 分别把成功和失败的回调存起来; 为了让链式调用正常进行下去,需要判断 onFulfilled 和 onRejected 的类型; onFulfilled 和 onRejected 需要被异步调用,这里用 setTimeout 模拟异步; 处理 Promise 的 resolve; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 const PENDING = 'pending' ;const FULFILLED = 'fulfilled' ;const REJECTED = 'rejected' ;class Promise { constructor (executor ) { this .status = PENDING; this .value = undefined ; this .reason = undefined ; this .onResolvedCallbacks = []; this .onRejectedCallbacks = []; let resolve = (value) = > { if (this .status === PENDING) { this .status = FULFILLED; this .value = value; this .onResolvedCallbacks.forEach((fn) = > fn()); } }; let reject = (reason) = > { if (this .status === PENDING) { this .status = REJECTED; this .reason = reason; this .onRejectedCallbacks.forEach((fn) = > fn()); } }; try { executor(resolve, reject); } catch (error) { reject(error); } } then (onFulfilled, onRejected ) { onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (v) = > v; onRejected = typeof onRejected === "function" ? onRejected : (err) = > { throw err; }; let promise2 = new Promise ((resolve, reject) = > { if (this .status === FULFILLED) { setTimeout (() = > { try { let x = onFulfilled(this .value); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }, 0 ); } if (this .status === REJECTED) { setTimeout (() = > { try { let x = onRejected(this .reason); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }, 0 ); } if (this .status === PENDING) { this .onResolvedCallbacks.push(() = > { setTimeout (() = > { try { let x = onFulfilled(this .value); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }, 0 ); }); this .onRejectedCallbacks.push(() = > { setTimeout (() = > { try { let x = onRejected(this .reason); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }, 0 ); }); } }); return promise2; } catch (error) { return this .then(null , error); } } const resolvePromise = (promise2, x, resolve, reject) = > { if (promise2 === x) { return reject( new TypeError ("Chaining cycle detected for promise #<Promise>" )); } let called; if ((typeof x === "object" && x != null ) || typeof x === "function" ) { try { let then = x.then; if (typeof then === "function" ) { then.call( x, (y) = > { if (called) return ; called = true ; resolvePromise(promise2, y, resolve, reject); }, (r) = > { if (called) return ; called = true ; reject(r); }); } else { resolve(x); } } catch (e) { if (called) return ; called = true ; reject(e); } } else { resolve(x); } };
Promise 写完之后可以通过 promises-aplus-tests 这个包对我们写的代码进行测试,看是否符合 A+ 规范。不过测试前还得加一段代码:
1 2 3 4 5 6 7 8 9 10 11 Promise .defer = Promise .deferred = function ( ) { let dfd = {} dfd.promise = new Promise ((resolve,reject )=> { dfd.resolve = resolve; dfd.reject = reject; }); return dfd; } module .exports = Promise ;
全局安装:
1 npm i promises-aplus-tests -g
终端下执行验证命令:
1 promises-aplus-tests promise.js
上面写的代码可以顺利通过全部 872 个测试用例。
参考:
Promise.resolve()
Promise.resolve(value)
可以将任何值转成值为 value 状态是 fulfilled 的 Promise,但如果传入的值本身是 Promise 则会原样返回它。
1 2 3 4 5 6 7 8 Promise .resolve = function (value ) { if (value instanceof Promise ){ return value } return new Promise (resolve => resolve(value)) }
参考:深入理解 Promise
Promise.reject()
和 Promise.resolve()
类似,Promise.reject()
会实例化一个 rejected 状态的 Promise。但与 Promise.resolve()
不同的是,如果给 Promise.reject()
传递一个 Promise 对象,则这个对象会成为新 Promise 的值。
1 2 3 4 Promise .reject = function (reason ) { return new Promise ((resolve, reject ) => reject(reason)) }
Promise.all()
传入的所有 Promise 都是 fulfilled,则返回由他们的值组成的,状态为 fulfilled 的新 Promise; 只要有一个 Promise 是 rejected,则返回 rejected 状态的新 Promise,且它的值是第一个 rejected 的 Promise 的值; 只要有一个 Promise 是 pending,则返回一个 pending 状态的新 Promise; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Promise .all = function (promiseArr ) { let index = 0 , result = [] return new Promise ((resolve, reject ) => { promiseArr.forEach((p, i ) => { Promise .resolve(p).then(val => { index++ result[i] = val if (index === promiseArr.length) { resolve(result) } }, err => { reject(err) }) }) }) }
Promise.race()
返回一个由所有可迭代实例中第一个 fulfilled 或 rejected 的实例包装后的新实例。
1 2 3 4 5 6 7 8 9 10 11 12 Promise .race = function (promiseArr ) { return new Promise ((resolve, reject ) => { promiseArr.forEach(p => { Promise .resolve(p).then(val => { resolve(val) }, err => { reject(err) }) }) }) }
Promise.allSettled()
所有 Promise 的状态都变化了,那么新返回一个状态是 fulfilled 的 Promise,且它的值是一个数组,数组的每项由所有 Promise 的值和状态组成的对象; 如果有一个是 pending 的 Promise,则返回一个状态是 pending 的新实例; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 Promise .allSettled = function (promiseArr ) { let result = [] return new Promise ((resolve, reject ) => { promiseArr.forEach((p, i ) => { Promise .resolve(p).then(val => { result.push({ status: 'fulfilled' , value: val }) if (result.length === promiseArr.length) { resolve(result) } }, err => { result.push({ status: 'rejected' , reason: err }) if (result.length === promiseArr.length) { resolve(result) } }) }) }) }
Promise.any()
空数组或者所有 Promise 都是 rejected,则返回状态是 rejected 的新 Promise,且值为 AggregateError 的错误; 只要有一个是 fulfilled 状态的,则返回第一个是 fulfilled 的新实例; 其他情况都会返回一个 pending 的新实例; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Promise .any = function (promiseArr ) { let index = 0 return new Promise ((resolve, reject ) => { if (promiseArr.length === 0 ) return promiseArr.forEach((p, i ) => { Promise .resolve(p).then(val => { resolve(val) }, err => { index++ if (index === promiseArr.length) { reject(new AggregateError('All promises were rejected' )) } }) }) }) }