How do I access previous promise results in a .then() chain? How do I access previous promise results in a .then() chain? javascript javascript

How do I access previous promise results in a .then() chain?


Break the chain

When you need to access the intermediate values in your chain, you should split your chain apart in those single pieces that you need. Instead of attaching one callback and somehow trying to use its parameter multiple times, attach multiple callbacks to the same promise - wherever you need the result value. Don't forget, a promise just represents (proxies) a future value! Next to deriving one promise from the other in a linear chain, use the promise combinators that are given to you by your library to build the result value.

This will result in a very straightforward control flow, clear composition of functionalities and therefore easy modularisation.

function getExample() {    var a = promiseA(…);    var b = a.then(function(resultA) {        // some processing        return promiseB(…);    });    return Promise.all([a, b]).then(function([resultA, resultB]) {        // more processing        return // something using both resultA and resultB    });}

Instead of the parameter destructuring in the callback after Promise.all that only became avail­able with ES6, in ES5 the then call would be replaced by a nifty helper method that was provided by many promise libraries (Q, Bluebird, when, …): .spread(function(resultA, resultB) { ….

Bluebird also features a dedicated join function to replace that Promise.all+spread combination with a simpler (and more efficient) construct:

return Promise.join(a, b, function(resultA, resultB) { … });


ECMAScript Harmony

Of course, this problem was recognized by the language designers as well. They did a lot of work and the async functions proposal finally made it into

ECMAScript 8

You don't need a single then invocation or callback function anymore, as in an asynchronous function (that returns a promise when being called) you can simply wait for promises to resolve directly. It also features arbitrary control structures like conditions, loops and try-catch-clauses, but for the sake of convenience we don't need them here:

async function getExample() {    var resultA = await promiseA(…);    // some processing    var resultB = await promiseB(…);    // more processing    return // something using both resultA and resultB}

ECMAScript 6

While we were waiting for ES8, we already did use a very similar kind of syntax. ES6 came with generator functions, which allow breaking the execution apart in pieces at arbitrarily placed yield keywords. Those slices can be run after each other, independently, even asynchronously - and that's just what we do when we want to wait for a promise resolution before running the next step.

There are dedicated libraries (like co or task.js), but also many promise libraries have helper functions (Q, Bluebird, when, …) that do this async step-by-step execution for you when you give them a generator function that yields promises.

var getExample = Promise.coroutine(function* () {//               ^^^^^^^^^^^^^^^^^ Bluebird syntax    var resultA = yield promiseA(…);    // some processing    var resultB = yield promiseB(…);    // more processing    return // something using both resultA and resultB});

This did work in Node.js since version 4.0, also a few browsers (or their dev editions) did support generator syntax relatively early.

ECMAScript 5

However, if you want/need to be backward-compatible you cannot use those without a transpiler. Both generator functions and async functions are supported by the current tooling, see for example the documentation of Babel on generators and async functions.

And then, there are also many other compile-to-JS languagesthat are dedicated to easing asynchronous programming. They usually use a syntax similar to await, (e.g. Iced CoffeeScript), but there are also others that feature a Haskell-like do-notation (e.g. LatteJs, monadic, PureScript or LispyScript).


Synchronous inspection

Assigning promises-for-later-needed-values to variables and then getting their value via synchronous inspection. The example uses bluebird's .value() method but many libraries provide similar method.

function getExample() {    var a = promiseA(…);    return a.then(function() {        // some processing        return promiseB(…);    }).then(function(resultB) {        // a is guaranteed to be fulfilled here so we can just retrieve its        // value synchronously        var aValue = a.value();    });}

This can be used for as many values as you like:

function getExample() {    var a = promiseA(…);    var b = a.then(function() {        return promiseB(…)    });    var c = b.then(function() {        return promiseC(…);    });    var d = c.then(function() {        return promiseD(…);    });    return d.then(function() {        return a.value() + b.value() + c.value() + d.value();    });}