The right pattern for multi-path streams with Promises

So, I have been playing with promises for the past few days and just trying to convert some kind of project to use promises, but more than a few times I came across this problem.

When reading articles and manuals, everything looks smooth and clean:

getDataFromDB() .then(makeCalculatons) .then(getDataFromDB) .then(serveToClient) 

But actually it is not.
There are many β€œconditions” in programs that change the entire flow:

 getDataFromCache(data).then(function(result){ if(result){ return result; }else{ return getDataFromDB(); } }).then(function(result){ if(result){ serveToClient() //this does not return a promise, so undefined returned... }else{ return getDataFromWebService(); //this does return a promise, } }).then(function(result){ //i dont want to reach here if i already serveToClient()... //so i basically have to check "if(result)" for all next thens if(result){ //do more stuff } }).then(... 

I have two main problems:

  • I find that I add a lot of if conditions to the then callbacks.
  • I still fall into the following then callbacks, even if I have already finished ( serveToClient )


Am I following the correct pattern?

+6
source share
2 answers

You cannot escape if , as this is necessary for your logical stream. You will need to control the flow of the branch if you do not want to continue the promise chain in one part of the if . Therefore, if in some part of your second .then() handler you do not want to go to the third .then() handler, then you need to separate the logic as follows and put the subsequent .then() handlers in the 2nd .then() in its branch of logic.

You cannot simply continue the top-level branch, because the only way to break the future .then() logic in the main chain is to either reject the promise (which you probably do not want to make), or add another if check each .then() handler to decide whether to skip it or not (yuck).

So you can split the logic as follows:

 getDataFromCache().then(function(result){ if(!result) { return getDataFromDB() } else { return result; } }).then(function(result){ // branch promise chain here into two separate branches if(result){ // do not continue the promise chain here // call a synchronous operation serveToClient(); } else { // continue promise chain here return getDataFromWebService().then(function(result) { if(result){ //do more stuff } }).then(...); // you can continue the promise chain here } }).catch(function(err) { // process any errors here }); 

You may find these other answers helpful:

Understanding javascript promises; stacks and chain

Is there a difference between a promise. then .then vs prom.then; promise.then


FYI, you can reorganize the above code to be a little more concise, for example:

 getDataFromCache().then(function(result) { if (result) serveToClient(); } else { return getDataFromWebService().then(function(result) { if(result){ //do more stuff } }).then(...); // you can continue the promise chain here } }).catch(function(err) { // process any errors here }); 
+5
source

Another answer explains the fork, but you also asked "smoothly and cleanly."

You can use the ES6 arrow functions :

 getDataFromCache() .then(result => result || getDataFromDB()) .then(result => result ? serveToClient() : getDataFromWebService() .then(result => { /* Won't reach here if serveToClient */ })) .then(() => { /* can continue promise chain here */ }) .catch(e => console.log(e)); 

Note that the .then padding is on getDataFromWebService() and see double )) in the tail. This perfectly reflects synchronous branching.

You can use ES8 async / await (now available in Chrome Canary and Firefox Nightly !):

 try { if (await getDataFromCache() || await getDataFromDB()) { serveToClient(); } else { let result = await getDataFromWebService(); /* Won't reach here if serveToClient */ } /* can continue here */ } catch (e) { // process any errors here } 

The latter gives you full control, as if everything was synchronous if it is inside async functions .

+2
source

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


All Articles