Search code examples
javascriptpromisees6-promise

after adding a listener to a Promise, should I use the original promise or the new one?


I have some javasript code that takes an existing promise (say, the promise returned by fetch()) and adds value (say, then/catch listeners for debugging, or maybe more):

let myFetch = function(url) {
  return fetch(url).then(function(value) {
    console.log("fetch succeeded: value=",value);
    return value;
  }.catch(function(reason) {
    console.log("fetch failed: reason=",reason);
    throw reason;
  });
};

I found myself modifying the above code so that the listeners are added only if some condition is true:

let myFetch = function(url) {
  let promise = fetch(url);
  if (some condition) {
    promise = promise.then(function(value) {
      console.log("fetch succeeded: value=",value);
      return value;
    }.catch(function(reason) {
      console.log("fetch failed: reason=",reason);
      throw reason;
    });
  }
  return promise;
};

Now I'm wondering, does it really make sense for myFetch to return the new promise returned by "then" (actually catch which is shorthand for another "then") as above, or would it make more sense for it to return the original promise (with the added listeners)? In other words, I'm thinking of leaving out the second "promise =", so that the code will look like this instead:

let myFetch = function(url) {
  let promise = fetch(url);
  if (some condition) {
    promise.then(function(value) {
      console.log("fetch succeeded: value=",value);
      return value;
    }.catch(function(reason) {
      console.log("fetch failed: reason=",reason);
      throw reason;
    });
  }
  return promise;
};

Is that effectively different from the previous version? Is either version preferable, and if so, why?


Solution

  • If your only use case is logging something in then/catch – it shouldn't matter as long as everything goes well. Things get more messed if you get an exception. Consider these two examples:

    Return original promise

    function myFetch() {
        let promise = new Promise(function (resolve, reject) {
            resolve(100);
        });
        promise.then(function () { throw new Error('x'); });
        return promise;
    }
    
    myFetch().then(function () {
        console.log('success!');
    }).catch(function (e) {
        console.error('error!', e)
    });
    

    The result is success and the error thrown in the inner then might get swallowed in some promise libraries (although the most popular ones such as Bluebird handle this and you get additional error Unhandled rejection Error: x). The error might also get swallowed when using native Promises in some environments.

    Returning modified promise

    function myFetch() {
        let promise = new Promise(function (resolve, reject) {
            resolve(100);
        });
        promise = promise.then(function () { throw new Error('x'); });
        return promise;
    }
    
    myFetch().then(function () {
        console.log('success!');
    }).catch(function (e) {
        console.error('error!', e)
    });
    

    Now the result is error! Error: x.