How to correctly express arbitrary Promise chains without "indentation pyramids"?
Because of the way that subsequent operations rely on multiple bits of previous operations, your choices are:
Do what you've done
Put the variables outside the chain and assign them as you go
Have the entire thing passing around an object with
a
,b
, and such on it as properties
#1 is what I'd stick with, barring a really good reason to do either of the other two. Fortunately, that kind of accumulation rarely goes as deep as shown in your question.
async
/await
is the way to do it here some years later (and may have been when the question was posted, the proposal was finished and they could be used with a transpiler), see Sterling's answer for how they could simplify it. Here's a working example:
const F = x => {
return new Promise(resolve => {
setTimeout(() => {
resolve(x);
}, 100);
});
};
(async () => {
const a = await F(100);
const b = await F(200);
const c = await F(a+b);
const d = await F(a+c);
const e = await F(b+c);
const f = await F(d+e);
console.log(f);
})()
.catch(error => {
// ...handle/report error...
});
Live on Babel's REPL for those with outdated environments.
Second try. @Luggage in the JS chat suggested using Async/Await to keep the scope of your params.
let a = await F(200);
let b = await F(a + 100);
let c = await F(a + b);
//... etc, all inside an async function
You could also use Promise.all
or (this is my experience) I've used the async
lib to help waterfall these issues.
async.waterfall([
(callback) => {
let a = F(200);
callback(null, a)
}, (a, callback) => {
let b = F(a+b);
callback(null, b);
}, //etc down the chain
]);
I think Promise.all
would manage it better than an async lib, but async/await is the prettiest method here, though it will require ES2017 support/transpiling.
Async/await solve this issue quite nicely I think;
async function runAsync(){
const F = async (x) => x;
const a = await F(1);
const b = await F(2);
const c = await F(a + b);
const d = await F(a + c);
const e = await F(b + c);
console.log(e);
}
function runSync(){
const F = (x) => x;
const a = F(1);
const b = F(2);
const c = F(a + b);
const d = F(a + c);
const e = F(b + c);
console.log(e);
}
runSync(); //5
runAsync(); //5
this will run natively with node 7 using node --harmony-async-await example
Unfortunately, you'll likely need to transpile down for general use and the output can get quite large.