想象一下以下基于Promise的例子:
function treadLightly() {
return Promise.resolve()
.then(function() { allocateResource(); })
.then(function() { doRiskyOperation(); })
.then(function() { releaseResource(); })
.catch(function() { releaseResource(); })
;
}
我们要致电releaseResource()
,无论doRiskyOperation()
是否已解决或拒绝。但是在两个不同的地方调用releaseResource()
时会有一股代码味道。
我们真正想要的是与javascript finally
等效的内容。
是否有更简洁的方法在Promises中对此进行编码?
答案 0 :(得分:5)
ES2015(ES6)承诺不会finally
。它有一个Stage 2 proposal,这意味着它基本没有机会进入ES2017,但它有可能出现在ES2018中。我还没有看到一个非常好的模式(而不是实际的finally
功能)。
某些第三方承诺库拥有它,包括Bluebird,Q和when。 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(() => {
...
});