❗实现一个 Promise(2)
除了 then 以外的所有方法
上一篇实现了 Promise 的核心方法 then()
,本篇将在此基础上实现 Promise 的其它 instance method(实例方法)和 static method(静态方法)。
说明:
在基于
then()
实现其它方法时,选择了用then-catch-finally
的形式,主要是为了代码的可读性。理论上,底层库更应该用then()
的双参数形式,毕竟会少返回一两层 promise。这里就不考虑不同的 Promise 实现之间的 interoperability(互操作)了,比如在
resolve()
里直接判断x instanceof MyPromise
,比如在其它方法里直接调用MyPromise.resolve()
。毕竟 Promise 已经成为语言的正式标准也有七八年了,再加上本文的主要目的是想“通过自己实现一个 Promise 来更好地理解其原理”。
1. 实例方法
then()
是 Promise 的 primitive(原始)方法,catch()
和 finally()
都是基于它实现的。
1.1 Promise.prototype.then()
Promise.prototype.then()
具体的代码实现,详见上一篇:实现一个符合 Promises/A+ 规范的 Promise。
1.2 Promise.prototype.catch()
Promise.prototype.catch()
相当于 then()
的简写,代码如下:
1.3 Promise.prototype.finally()
Promise.prototype.finally()
是在 then()
的基础上实现的,也返回一个 promise(便于链式调用),不过逻辑上有以下不同:
只有一个回调参数,可以理解为形如
then(onFinally, onFinally)
调用时机:无论是 fulfilled 还是 rejected,都会被调用(因此通常用来处理二者的公共逻辑)
在调用链上,如何从前面接值:该回调函数没有参数,即不接收上一个
then
的执行结果在调用链上,如何向后面传值:
如果回调函数的执行正常,则单纯透传上一个
then
的执行结果(包括 fulfilled 和 rejected)如果回调函数的执行被 reject 了,则它会把自身的异常结果传下去,即触发下一个
then
的 reject 逻辑
可以运行以下代码,感受 finally()
的用法:
finally()
的代码示意,如下:
注意:finally()
的执行顺序取决于它在 then()
链式调用里的顺序,而并不是要“最后”执行。比如:
结合 finally
函数的功能语义,感觉它叫 settled
会更合适。但是考虑到它的使用场景,通常是处理一些不论是 fulfilled 还是 rejected 的通用逻辑,因此大多数情况都是放在链式调用的最后;即便是在中间位置,也是对上一个 then
的 finally 处理。站在这个角度理解,名字叫 finally
也说得通。
2. 静态方法
2.1 Promise.resolve()
Promise.resolve()
要么返回一个新的 promise,要么返回参数本身。
代码示意,如下:
通常,当我们不知道某个值是不是 promise 时,就可以用 Promise.resolve(x)
将其显式地转为 promise。
2.2 Promise.reject()
Promise.reject()
返回一个新的 promise 对象,用给定的 reason 来 reject。
3. 静态方法之并发
async task concurrency,异步任务并发
JavaScript 本质上是 single-threaded(单线程的),因此在给定的瞬间只有一个 task 被执行,虽然看起来是并发的。JavaScript 中的 parallel execution(并行执行)只能通过 worker threads(工作线程)来实现。
Promise 类提供了 4 种 static method 来处理异步任务并发,包括:
Promise.race()
ES2015,ES6Promise.all()
ES2015,ES6Promise.allSettled()
ES2020Promise.any()
ES2021
它们都接收一个 iterable promises(准确地说是 thenables),然后返回一个新的 promise。其中,iterable 可能包含一个或多个 non-promise value 或已经 settled 的 promise。
3.0 参数说明
(1)参数必须是 iterable
判断一个值是不是 iterable(可迭代的),代码如下:
内置的可迭代对象有 String
, Array
, TypedArray
, Map
, Set
, Segments
以及 arguments
, NodeList
和 function*
, async function*
。
当参数不是 iterable(可迭代的)时,会报错。如下:
(2)当参数是 empty 时
当参数是 empty iterable 时,不同方法的处理结果不同。如下:
race()
必须
永远 pending
all()
必须
fulfilled []
allSettled()
必须
fulfilled []
any()
必须
rejected
AggregateError: All promises were rejected
(3)当包含 non-promise value 时
参数里可能包含 non-promise value,所以统一用 Promise.resolve(p)
处理成 promise。
(4)当包含已经 settled 的 promise 时
对于参数里已经 settled 的 promise,依然按照异步的逻辑执行,即不做特殊处理。
不是 pending 状态的 promise,就称它已经 settled 了,既可以 fulfilled 也可以 rejected。
3.1 Promise.race()
Promise.race()
返回一个新的 promise,用最先 settled 的结果来 settle。
代码示意,如下:
3.2 Promise.all()
Promise.all()
返回一个新的 promise,要么是用所有 values 的数组来 fulfill,要么是用最先到的 reason 来 reject。
代码示意,如下:
3.3 Promise.allSettled()
Promise.allSettled()
返回一个新的 promise,用一个 promise state snapshots 数组来 fulfill,且是在所有原始 promises 都 settled 了(可以 fulfilled 也可以 rejected)。
代码示意,如下:
3.4 Promise.any()
Promise.any()
返回一个新的 promise,要么是用最先 fulfilled promise 来 fulfill,要么是用包含所有 reasons 的聚合错误来 reject。
代码示意,如下:
Last updated