📝实现一个 Promise(3)

关于 Promise 的其它问题

1. 如何停止一个 promise 链?

站在实现者的角度,当发生严重错误致使后面的链都没必要执行了的时候,可以返回一个永远 pending 的 promise。

return new Promise(() => { })

但是,它会引入一个新的问题:链式调用后面的所有回调函数,都将无法被垃圾回收器回收。

Promise 应该在执行完所有回调后,删除对所有回调函数的引用以让它们能被回收。在之前自己实现 Promise 时,为了减少复杂度,并没有做这种处理。

思考:能否用一个函数变量或函数定义,来替代上面的匿名函数?答案是可以的,这样的话整个 promise 链就只有一份在内存里,不被回收也是可以接受的。

// 将其封装成一个更有语义的函数,提高可读性
Promise.cancel = Promise.stop = function () {
    return new Promise(() => { })
}

然后,就可以这样停止 promise 链了:

new Promise((resolve, reject) => {
    resolve(35)
}).then((value) => {
    // ...这里发生了严重错误
    return Promise.stop() // 返回一个永远 pending 的 promise
}).catch()
  .then()
  .then()
  .catch()
  .then()

2. 链上最后一个 promise 出错了怎么办?

在所有 promise 链的最后都加上 catch(),是可以确保之前发生的错误都能被捕获。然而,如果是最后一个 catch() 里出错了,如何捕捉?

2.1 新增 done()

方法一:提供一个 done 方法,将其列在链的最后。

就可以这样使用了:

本质上,这和开发人员在每个链后自己加 catch 没太大区别,只是函数由框架提供了而已。Q 就使用了 done 方法来达成类似的目的,$q 在最新的版本中也加入了类似的功能。

2.2 完善 reject 逻辑

方法二:在实现 Promise 的 reject 的逻辑里,增加如下判断:

比如在执行如下代码时,由于 promise4 是真的没有任何回调,所以就会触发新增的 console.error()

Bluebird 和 ES6 Promise 都做了类似的处理,在 promise 被 reject 但又没有 callback 时,就把错误输出到控制台。

Last updated