Promises, pass additional parameters to then chain

114,950

Solution 1

You can use Function.prototype.bind to create a new function with a value passed to its first argument, like this

P.then(doWork.bind(null, 'text'))

and you can change doWork to,

function doWork(text, data) {
  consoleToLog(data);
}

Now, text will be actually 'text' in doWork and data will be the value resolved by the Promise.

Note: Please make sure that you attach a rejection handler to your promise chain.


Working program: Live copy on Babel's REPL

function doWork(text, data) {
  console.log(text + data + text);
}

new Promise(function (resolve, reject) {
    var a = 5;
    if (a) {
      setTimeout(function () {
        resolve(a);
      }, 3000);
    } else {
      reject(a);
    }
  })
  .then(doWork.bind(null, 'text'))
  .catch(console.error);

Solution 2

Perhaps the most straightforward answer is:

P.then(function(data) { return doWork('text', data); });

Or, since this is tagged ecmascript-6, using arrow functions:

P.then(data => doWork('text', data));

I find this most readable, and not too much to write.

Solution 3

Use currying.

var P = new Promise(function (resolve, reject) {
    var a = 5;
    if (a) {
        setTimeout(function(){
            resolve(a);
        }, 3000);
    } else {
        reject(a);
    }
});

var curriedDoWork = function(text) {
    return function(data) {
        console.log(data + text);
    }
};

P.then(curriedDoWork('text'))
.catch(
    //some error handling
);

Solution 4

The new answer to this question is to use arrow functions (which automatically bind the this and are much more readable). Google for links such as: https://2ality.com/2016/02/arrow-functions-vs-bind.html

You can set the text like:

this.text = 'text';
P.then(data => doWork(data));

Note: this.text inside doWork will evaluate to 'text'.

This is suggested by jib above and that (or this!) should be the accepted answer now.

Share:
114,950

Related videos on Youtube

user3110667
Author by

user3110667

Updated on July 08, 2022

Comments

  • user3110667
    user3110667 almost 2 years

    A promise, just for example:

    var P = new Promise(function (resolve, reject) {
      var a = 5;
      if (a) {
        setTimeout(function(){
          resolve(a);
        }, 3000);
      } else {
        reject(a);
      }
    });
    

    After we call the .then() method on the promise:

    P.then(doWork('text'));
    

    Then doWork function looks like this:

    function doWork(data) {
      return function(text) {
        // sample function to console log
        consoleToLog(data);
        consoleToLog(b);
      }
    }
    

    How can I avoid returning an inner function in doWork, to get access to data from the promise and text parameters? Are there any tricks to avoiding the inner function?

    • Admin
      Admin almost 8 years
      Why would anyone intentionally renounce currying? In order to use the hideous bind method? - which is also extremely slow.
    • Roland
      Roland over 6 years
      @ftor I don't understand you, can you please provide some code for clarification?
  • user3110667
    user3110667 over 8 years
    thanks, that helps, earlier i try doWork.call(this, 'text'), but data was replaced by 'text'
  • sdgluck
    sdgluck over 8 years
    call invokes a function in-place, bind creates a new function, however both accept an execution context as their first argument.
  • Flame
    Flame about 6 years
    b careful with this, if you create curriedDoWork into a promise by doing return new Promise() on the first line of this function, the promise is executed as soon as you call curriedDoWork() (like you do in ..then(curriedDoWork('text'))
  • germain
    germain almost 6 years
    @Flame: short answer, for your convenience you can wrap the promise into a function, if you like to do so.
  • germain
    germain almost 6 years
    @yks, you could have indicated this syntax which is quite interesting const curriedWork = text => data => console.log(data + text)
  • yks
    yks almost 6 years
    @germain ah yes i have seen this form before, gotta love functional programming. However i experience arrow functions break in some browser, so i tend to avoid it now.
  • germain
    germain almost 6 years
    @yks, only Internet Explorer doesn't support it and will never, because of Edge, Internet Explorer last build was December 9th 2015. Let's move on ~
  • Reahreic
    Reahreic about 3 years
    In your es6 example & 'classes' how would I go about replacing "text" with a reference to an item in an array I was iterating through when creating the promise. EG: fetch(request).then(data => this.AssetRetrieved(jData.parms[i].Value, data));
  • jib
    jib about 3 years
    @Reahreic That sounds like a variation of the JS closures in a loop problem. Is this answer helpful? If not, please consider asking a new question with more details.