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

时间:2016-08-08 13:19:45

标签: javascript asynchronous promise chain

使用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

在[{1}}情况下,我所寻找的内容与finally类似。

PS:我在NodeJS上使用ES6 Promise polyfill

2 个答案:

答案 0 :(得分:13)

如果您从catch返回值,则可以then使用catch

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 resolution:", result);
      return result;
    },
    error => {
      console.log(name, "initial rejection; propagating it");
      throw error;
    }
  )
  .finally(() => {
    console.log(name, "in finally");
  })
  .then(
    result => {
      console.log(name, "resolved:", result);
    },
    error => {
      console.log(name, "rejected:", error);
    }
  );
}




关于这一点的几点说明:

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

  2. 上述故意包括finally回调的任何参数,并且没有表明承诺是否得到解决或拒绝,以便与{{ 1}}在经典的finally结构中。但如果有人想要,可以轻松地将一些信息传递给回调。

  3. 同样,以上内容不使用try-catch-finally回调返回的值,除非,如果它是承诺,它会在允许之前等待承诺结算链条继续。

  4. 这是ES5的翻译:

    finally

    示例:

    
    
    (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;
                        });
                    }
                );
            }
        });
    })();
    
    
    
    

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

    或者,如果您更喜欢子类(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 resolution:", 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, "resolved:", result); }, function(error) { console.log(name, "rejected:", error); } ); }而不是修改其原型:

    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 resolution:", result); return result; }, error => { console.log(name, "initial rejection; propagating it"); throw error; } ) .finally(() => { console.log(name, "in finally"); }) .then( result => { console.log(name, "resolved:", result); }, error => { console.log(name, "rejected:", error); } ); } 子类的情况下执行此操作。在ES5中,效用函数非常难以使用,因为您必须将承诺传递给它,这与正常的承诺使用完全不一致。在ES2015中,可以做一些更自然的事情,但是调用它比修改原型或子类化更令人痛苦:

    Promise.prototype

    用法:

    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; })
            ];
        }
    })();
    

    注意使用扩展运算符(这就是为什么它不能在ES5中工作),因此thePromise.then(...always(/*..your function..*/)). 可以为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 resolution:", 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, "resolved:", result); }, error => { console.log(name, "rejected:", error); } ); }不会等待承诺;这是最后一个finally示例,延迟证明它确实如此:

    
    
    always
    
    
    

答案 1 :(得分:3)

ES2015代码:

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