繁体   English   中英

承诺:执行某事而不管解决/拒绝?

[英]Promises: Execute something regardless of resolve/reject?

使用 Promises 设计模式,是否可以实现以下内容:

 var a, promise

 if promise.resolve
     a = promise.responsevalue;

 if promise.reject
     a = "failed"

 AFTER resolution/rejection. Not ASYNC!!
     send a somewhere, but not asynchronously. //Not a promise

我正在寻找的是finallytry - catch情况下的东西。

PS:我在 NodeJS 上使用 ES6 Promise polyfill

注意: finally现在是 JavaScript 承诺的标准部分,所以你可以这样做:

thePromise.then(result => doSomething(result)
          .catch(error => handleOrReportError(error))
          .finally(() => doSomethingAfterFulfillmentOrRejection());

之前的回答finally是标准的:


如果您从catch返回一个值,那么您可以在catch的结果上使用then

thePromise.then(result => doSomething(result)
          .catch(error => handleErrorAndReturnSomething(error))
          .then(resultOrReturnFromCatch => /* ... */);

...但这意味着您正在将拒绝转换为实现(通过从catch返回一些东西而不是抛出或返回被拒绝的承诺),并且依赖于这个事实。


如果你想要一些东西在不修改的情况下透明地传递履行/拒绝,ES2015(“ES6”)承诺中没有任何东西可以做到这一点(编辑:再次,现在有),但它很容易编写(这是在 ES2015 ,但我在下面有一个 ES5 翻译):

{
    let worker = (p, f, done) => {
        return p.constructor.resolve(f()).then(done, done);
    };
    Object.defineProperty(Promise.prototype, "finally", {
        value(f) {
            return this.then(
                result => worker(this, f, () => result),
                error  => worker(this, f, () => { throw error; })
            );
        }
    });
}

示例:

 { let worker = (p, f, done) => { return p.constructor.resolve(f()).then(done, done); }; Object.defineProperty(Promise.prototype, "finally", { value(f) { return this.then( result => worker(this, f, () => result), error => worker(this, f, () => { throw error; }) ); } }); } test("p1", Promise.resolve("good")).finally( () => { test("p2", Promise.reject("bad")); } ); function test(name, p) { return p.then( result => { console.log(name, "initial fulfillment:", result); return result; }, error => { console.log(name, "initial rejection; propagating it"); throw error; } ) .finally(() => { console.log(name, "in finally"); }) .then( result => { console.log(name, "fulfilled:", result); }, error => { console.log(name, "rejected:", error); } ); }

对此有几点说明:

  1. 请注意this.constructor的使用,以便我们在创建原始承诺的任何类型的承诺(包括可能的子类)上调用resolve 这与Promise.resolve和其他人的工作方式一致,并且是支持子类承诺的重要部分。

  2. 以上是故意包括任何参数的finally回调,并没有承诺是否应验或拒绝指示,为了要符合finally在经典try-catch-finally结构。 但如果需要,可以轻松地将其中一些信息传递到回调中。

  3. 同样,上面并没有使用返回的值的finally回调只是如果它是一个承诺,它使链条继续之前等待的承诺来解决。

这是它的 ES5 翻译:

(function() {
    function worker(ctor, f, done) {
        return ctor.resolve(f()).then(done, done);
    }
    Object.defineProperty(Promise.prototype, "finally", {
        value: function(f) {
            var ctor = this.constructor;
            return this.then(
                function(result) {
                    return worker(ctor, f, function() {
                        return result;
                    });
                },
                function(error) {
                    return worker(ctor, f, function() {
                        throw error;
                    });
                }
            );
        }
    });
})();

示例:

 (function() { function worker(ctor, f, done) { return ctor.resolve(f()).then(done, done); } Object.defineProperty(Promise.prototype, "finally", { value: function(f) { var ctor = this.constructor; return this.then( function(result) { return worker(ctor, f, function() { return result; }); }, function(error) { return worker(ctor, f, function() { throw error; }); } ); } }); })(); test("p1", Promise.resolve("good")).finally(function() { test("p2", Promise.reject("bad")); }); function test(name, p) { return p.then( function(result) { console.log(name, "initial fulfillment:", result); return result; }, function(error) { console.log(name, "initial rejection; propagating it"); throw error; } ) .finally(function() { console.log(name, "in finally"); }) .then( function(result) { console.log(name, "fulfilled:", result); }, function(error) { console.log(name, "rejected:", error); } ); }

我认为这是将这个功能集成到 ES5 中的 Promise polyfill 的最简单方法。


或者,如果您更喜欢继承Promise而不是修改其原型:

let PromiseX = (() => {
    let worker = (p, f, done) => {
        return p.constructor.resolve(f()).then(done, done);
    };
    class PromiseX extends Promise {
        finally(f) {
            return this.then(
                result => worker(this, f, () => result),
                error  => worker(this, f, () => { throw error; })
            );
        }
    }
    PromiseX.resolve = Promise.resolve;
    PromiseX.reject = Promise.reject;

    return PromiseX;
})();

示例:

 let PromiseX = (() => { let worker = (p, f, done) => { return p.constructor.resolve(f()).then(done, done); }; class PromiseX extends Promise { finally(f) { return this.then( result => worker(this, f, () => result), error => worker(this, f, () => { throw error; }) ); } } PromiseX.resolve = Promise.resolve; PromiseX.reject = Promise.reject; return PromiseX; })(); test("p1", PromiseX.resolve("good")).finally( () => { test("p2", PromiseX.reject("bad")); } ); function test(name, p) { return p.then( result => { console.log(name, "initial fulfillment:", result); return result; }, error => { console.log(name, "initial rejection; propagating it"); throw error; } ) .finally(() => { console.log(name, "in finally"); }) .then( result => { console.log(name, "fulfilled:", result); }, error => { console.log(name, "rejected:", error); } ); }


你已经说过你想要在不扩展Promise.prototype子类化的情况下完成它。 在 ES5 中,实用程序函数使用起来非常笨拙,因为您必须将要执行的承诺传递给它,这与正常的承诺用法完全不符。 在 ES2015 中,可以做一些更自然的事情,但调用仍然比修改原型或子类化更痛苦:

let always = (() => {
    let worker = (f, done) => {
        return Promise.resolve(f()).then(done, done);
    };
    return function always(f) {
        return [
            result => worker(f, () => result),
            error  => worker(f, () => { throw error; })
        ];
    }
})();

用法:

thePromise.then(...always(/*..your function..*/)).

请注意扩展运算符的使用(这就是为什么这在 ES5 中不起作用),因此always可以向then提供两个参数。

示例:

 let always = (() => { let worker = (f, done) => { return Promise.resolve(f()).then(done, done); }; return function always(f) { return [ result => worker(f, () => result), error => worker(f, () => { throw error; }) ]; } })(); test("p1", Promise.resolve("good")).then(...always( () => { test("p2", Promise.reject("bad")); } )); function test(name, p) { return p.then( result => { console.log(name, "initial fulfillment:", result); return result; }, error => { console.log(name, "initial rejection; propagating it"); throw error; } ) .then(...always(() => { console.log(name, "in finally"); })) .then( result => { console.log(name, "fulfilled:", result); }, error => { console.log(name, "rejected:", error); } ); }


在评论中,您表达了对finally不会等待承诺的担忧; 这是最后一个always例子,延迟证明它确实如此:

 let always = (() => { let worker = (f, done) => { return Promise.resolve(f()).then(done, done); }; return function always(f) { return [ result => worker(f, () => result), error => worker(f, () => { throw error; }) ]; } })(); test("p1", 500, false, "good").then(...always( () => { test("p2", 500, true, "bad"); } )); function test(name, delay, fail, value) { // Make our test promise let p = new Promise((resolve, reject) => { console.log(name, `created with ${delay}ms delay before settling`); setTimeout(() => { if (fail) { console.log(name, "rejecting"); reject(value); } else { console.log(name, "fulfilling"); resolve(value); } }, delay); }); // Use it return p.then( result => { console.log(name, "initial fulfillment:", result); return result; }, error => { console.log(name, "initial rejection; propagating it"); throw error; } ) .then(...always(() => { console.log(name, "in finally"); })) .then( result => { console.log(name, "fulfilled:", result); }, error => { console.log(name, "rejected:", error); } ); }

ES2015代码:

promise.then(val => val).catch(() => "failed").then(a => doSomethigWithA(a));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM