24.14 两个有用的 Promise 附加方法

本节介绍两个很有用的方法,这两个方法可以很容易的添加到 ES6 的 Promise 上面去。很多更全面的 Promise 库都有这两个方法。

24.14.1 done()

当你链接若干个 Promise 方法调用的时候,有一不小心忘记处理某些错误的风险。例如:

function doSomething() {
    asyncFunc()
    .then(f1)
    .catch(r1)
    .then(f2); // (A)
}

如果在行 A 的 then() 触发了拒绝( rejection ),那么这个错误将不会被处理。 Promise 库 Q 提供了一个方法 done() ,被用作链式调用的最后一个调用元素。 done() 要么替换掉最后一个 then() (此时有一到两个参数):

function doSomething() {
    asyncFunc()
    .then(f1)
    .catch(r1)
    .done(f2);
}

要么放在最后一个 then() 的后面(此时没有参数):

function doSomething() {
    asyncFunc()
    .then(f1)
    .catch(r1)
    .then(f2)
    .done();
}

引用 Q 的文档

donethen 使用的黄金规则就是:要么返回 Promise 给其它地方,要么调用 done 结束当前 Promise 链(如果这条链在当前位置结束的话)。用 catch 来结束 Promise 是不完美的,因为 catch 的处理器自身可能会抛出错误。

下面就是在 ECMAScript 6 中实现 done() 的方式:

Promise.prototype.done = function (onFulfilled, onRejected) {
    this.then(onFulfilled, onRejected)
    .catch(function (reason) {
        // Throw an exception globally
        setTimeout(() => { throw reason }, 0);
    });
};

虽然 done 的功能很有用,但是还是没有添加到 ECMAScript 6 中去,因为这种检查可以通过引擎自动实现(正如在调试 Promise 的那一节看到的一样)。

24.14.2 finally()

有时你想执行一些操作而不管是否发生了错误。例如,在操作完一个资源之后做一些清理工作。这就是 Promise 方法 finally 适用的场景,它和异常处理中的 finally 子句很相似。它的回调函数不接收参数,但是不管是 rejected 还是 resolved 状态都会被调用。

createResource(···)
.then(function (value1) {
    // Use resource
})
.then(function (value2) {
    // Use resource
})
.finally(function () {
    // Clean up
});

下面是 Domenic Denicola 提议的实现 finally() 的方式:

Promise.prototype.finally = function (callback) {
    let P = this.constructor;
    // We don’t invoke the callback in here,
    // because we want then() to handle its exceptions
    return this.then(
        // Callback fulfills => continue with receiver’s fulfillment or rejection
        // Callback rejects => pass on that rejection (then() has no 2nd paramet\
er!)
        value  => P.resolve(callback()).then(() => value),
        reason => P.resolve(callback()).then(() => { throw reason })
    );
};

回调函数决定了接收器( this )的稳定状态处理的方式:

  • 如果回调函数抛出异常或者返回一个 rejected 状态的 Promise ,则会变成拒绝值( rejection value )。
  • 否则,接收器的稳定状态( fulfilled 或者 rejected )变成了 finally() 返回的 Promise 的稳定状态。在某种程度上,我们把 finally 从方法链上脱离出来了。

示例1(作者 Jake Archibald )使用 finally() 隐藏一个 spinner 。简单的版本:

showSpinner();
fetchGalleryData()
.then(data => updateGallery(data))
.catch(showNoDataError)
.finally(hideSpinner);

示例2(作者 Kris Kowal )使用 finally() 拆分一个测试:

let HTTP = require("q-io/http");
let server = HTTP.Server(app);
return server.listen(0)
.then(function () {
    // run test
})
.finally(server.stop);

results matching ""

    No results matching ""