javascript - Promises: Execute something regardless of resolve/reject? -


using promises design pattern, possible implement following:

 var a, promise   if promise.resolve      = promise.responsevalue;   if promise.reject      = "failed"   after resolution/rejection. not async!!      send somewhere, not asynchronously. //not promise 

what i'm looking finally in try - catch situation.

ps: i'm using es6 promise polyfill on nodejs

if return value catch, can use then on result of catch.

thepromise.then(result => dosomething(result)           .catch(error => handleerrorandreturnsomething(error))           .then(resultorreturnfromcatch => /* ... */); 

...but means you're converting rejection resolution (by returning catch rather throwing or returning rejected promise), , relies on fact.


if want transparently passes along resolution/rejection without modifying it, there's nothing built es2015 ("es6") promises that, it's easy write (this in es2015, have es5 translation below):

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

example:

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

a couple of notes on that:

  1. note use of this.constructor we're calling resolve on whatever kind of promise (including possible subclass) created original promise; consistent how promise.resolve , others work, , important part of supporting subclassed promises.

  2. the above intentionally not including argument finally callback, , no indication of whether promise resolved or rejected, in order consistent finally in classic try-catch-finally structure. if 1 wanted, 1 pass of information callback.

  3. similarly, above not use value returned finally callback except if it's promise, waits promise settle before allowing chain continue.

here's es5 translation of that:

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

example:

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

i think simplest way integrate functionality promise polyfill in es5.


or if prefer subclass promise rather modifying prototype:

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

example:

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


you've said want without either extending promise.prototype or subclassing. in es5, utility function extremely awkward use, because you'd have pass promise act on, out of step normal promise usage. in es2015, it's possible more natural it's still more of pain call either modifying prototype or subclassing:

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

usage:

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

note use of spread operator (which why won't work in es5), always can supply both arguments then.

example:

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


in comments expressed concern finally wouldn't wait promise; here's last always example again, delays demonstrate does:

let = (() => {    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 ${delay}ms delay before settling`);      settimeout(() => {        if (fail) {          console.log(name, "rejecting");          reject(value);        } else {          console.log(name, "resolving");          resolve(value);        }      }, delay);    });      // use    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);      }    );  }


Comments

Popular posts from this blog

Spring Boot + JPA + Hibernate: Unable to locate persister -

go - Golang: panic: runtime error: invalid memory address or nil pointer dereference using bufio.Scanner -

c - double free or corruption (fasttop) -