Promises有“终极”模式吗?

时间:2016-12-28 14:58:25

标签: javascript promise

想象一下以下基于Promise的例子:

function treadLightly() {
  return Promise.resolve()
    .then(function() { allocateResource(); })
    .then(function() { doRiskyOperation(); })
    .then(function() { releaseResource(); })
    .catch(function() { releaseResource(); })
  ;
}

我们要致电releaseResource(),无论doRiskyOperation()是否已解决或拒绝。但是在两个不同的地方调用releaseResource()时会有一股代码味道。

我们真正想要的是与javascript finally等效的内容。

是否有更简洁的方法在Promises中对此进行编码?

3 个答案:

答案 0 :(得分:5)

ES2015(ES6)承诺不会finally 。它有一个Stage 2 proposal,这意味着它基本没有机会进入ES2017,但它有可能出现在ES2018中。我还没有看到一个非常好的模式(而不是实际的finally功能)。

某些第三方承诺库拥有它,包括BluebirdQwhen。 jQuery的Deferred的承诺也以always的形式出现。

该提案有polyfill您可以使用:

if (typeof Promise !== 'function') {
    throw new TypeError('A global Promise is required');
}

if (typeof Promise.prototype.finally !== 'function') {
    var speciesConstructor = function (O, defaultConstructor) {
        var C = typeof O.constructor === 'undefined' ? defaultConstructor : O.constructor;
        var S = C[Symbol.species];
        return S == null ? defaultConstructor : S;

        var C = O.constructor;
        if (typeof C === 'undefined') {
            return defaultConstructor;
        }
        if (!C || (typeof C !== 'object' && typeof C !== 'function')) {
            throw new TypeError('O.constructor is not an Object');
        }
        var S = C[Symbol.species];
        if (S == null) {
            return defaultConstructor;
        }
        if (typeof S === 'function' && S.prototype) {
            return S;
        }
        throw new TypeError('no constructor found');
    };
    var shim = {
        finally(onFinally) {
            var handler = typeof onFinally === 'function' ? onFinally : () => {};
            var C;
            var newPromise = Promise.prototype.then.call(
                this, // throw if IsPromise(this) is not true
                x => new C(resolve => resolve(handler())).then(() => x),
                e => new C(resolve => resolve(handler())).then(() => { throw e; })
            );
            C = speciesConstructor(this, Promise); // throws if SpeciesConstructor throws
            return newPromise;
        }
    };
    Promise.prototype.finally = shim.finally;
}

答案 1 :(得分:3)

虽然@T.J. Crowder's answer是正确的,但问题的实际解决方案可能是在最后添加另一个.then

function treadLightly() {
  return Promise.resolve()
    .then(function() { allocateResource(); })
    .then(function() { doRiskyOperation(); })
    .catch(function() { /* Do nothing, or log the error */ })
    .then(function() { releaseResource(); })
  ;
}

答案 2 :(得分:2)

  

有没有'终于'承诺的模式?

不通过本机(ES6)实现。但是,Bluebird具有此功能:

return new Promise((resolve, reject) => {
    ...
}).finally(() => {
    ...
});

.finally | bluebird