How to correctly express arbitrary Promise chains without "indent pyramids"?

There are methods such as Q.reduce and Q.all that help smooth out the promise chain for a particular case of dissimilar promises collections. Of course, the general case:

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

That is, a sequence of tasks on which each term depends on arbitrary previously defined members. Suppose F is an asynchronous call:

 const F = (x) => Q.delay(1000).return(x); 

I cannot express this pattern in any way without creating an indented pyramid:

 F(100).then(a => F(200).then(b => F(a+b).then(c => F(a+c).then(d => F(b+c).then(e => F(d+e).then(f => console.log(f) ) ) ) ) ) ); 

Note that using return values ​​will not work:

 F(100).then(a => F(200)) .then(b => F(a+b)) .then(c => F(a+c)) .then(d => F(b+c)) .then(e => F(d+e)) .then(f => console.log(f)); 

Since, for example, a will not be in scope in the second line. What is the right way to deal with this situation?

+6
source share
3 answers

Due to the fact that subsequent operations rely on several bits of previous operations, your options are:

  • Do what you did

  • Put the variables outside the chain and assign them when you go

  • Swipe the whole thing around the object with a , b , etc. on it like properties

# 1 is what I adhere to, with the exception of a really good reason to do either of the other two. Fortunately, such accumulation rarely goes as far as shown in your question.


If you want to accept async / await at the beginning (the sentence , they'll be in ES2017, and you can use them now with the transpiler), then see the Sterling answer for how they could simplify it. Here's a working example ( found on Babel REPL ):

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

Second attempt. @Luggage in chat JS suggested using Async / Await to keep your options area.

 let a = await F(200); let b = await F(a + 100); let c = await F(a + b); //... etc, all inside an async function 

You can also use Promise.all or (this is my experience). I used the async library to help solve these problems.

 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 that Promise.all will manage it better than async lib, but async / await is the most beautiful method here, although it will require ES2017 support / forwarding.

+3
source

Async / waiting to solve this problem pretty 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 be done initially with node 7 using node --harmony-async-await example

Unfortunately, you will most likely have to give up general use, and the output may become quite large.

+2
source

Source: https://habr.com/ru/post/1014132/


All Articles