Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly abort a node.js promise chain using Q?

Tags:

node.js

promise

q

I'm using the Q module for Node.js in attempts to avoid the "pyramid of doom" in scenarios where I have many steps. For example:

function doTask(task, callback) {     Q.ncall(task.step1, task)     .then(function(result1){         return Q.ncall(task.step2, task);     })     .then(function(result2){         return Q.ncall(task.step3, task);     })     .fail(callback).end(); } 

Essentially this seems to work; if an error is thrown by any of the task steps, it is passed to the callback (though I would be welcome to improvements, as I am new to node.js promises). However, I have a problem when I need to abort the task-chain early. For example, if result1 is successfully returned I might want to call the callback early and abort the rest, but my attempts to do so are failing...

function doTask(task, callback) {     Q.ncall(task.step1, task)     .then(function(result1){         if(result1)         {// the rest of the task chain is unnecessary              console.log('aborting!');             callback(null, result1);             return null;         }         return Q.ncall(task.step2, task);     })     .then(function(result2){         console.log('doing step 3...');         return Q.ncall(task.step3, task);     })     .fail(callback).end(); } 

In this example, I see both "aborting!" and "doing step 3..." printed.

I'm sure I'm merely misunderstanding some basic principles here, so would appreciate any help. Thanks!

like image 216
Zane Claes Avatar asked Jul 02 '12 22:07

Zane Claes


People also ask

How do you break out of a promise chain?

EDIT: Also keep in mind that if you want to break out of the chain in your error handler, it needs to return a rejected promise or throw an Error (which will be caught and wrapped in a rejected promise automatically). If you don't return a promise, then wraps the return value in a resolve promise for you.

How do you deal with promises in node?

The promise is resolved by calling resolve() if the promise is fulfilled, and rejected by calling reject() if it can't be fulfilled. Both resolve() and reject() takes one argument - boolean , string , number , array , or an object .

What is promise chaining in node JS?

Promise chaining: Promise chaining is a syntax that allows you to chain together multiple asynchronous tasks in a specific order. This is great for complex code where one asynchronous task needs to be performed after the completion of a different asynchronous task.

What does a promise return in node JS?

Promise. any() settles when any of the promises you pass to it fulfill or all of the promises get rejected. It returns a single promise that resolves with the value from the first promise that is fulfilled. If all promises are rejected, then the returned promise is rejected with an AggregateError .


2 Answers

This is a case where you will need to branch, which does mean either nesting or creating a subroutine.

function doTask(task, callback) {     return Q.ncall(task.step1, task)     .then(function(result1) {         if (result1) return result1;         return Q.ncall(task.step2, task)         .then(function(result2) {             return Q.ncall(task.step3, task);         })     })     .nodeify(callback) } 

Or

function doTask(task, callback) {     return Q.ncall(task.step1, task)     .then(function(result1) {         if (result1) {             return result1;         } else {             return continueTasks(task);         }     })     .nodeify(callback) }  function continueTasks(task) {     return Q.ncall(task.step2, task)     .then(function(result2) {         return Q.ncall(task.step3, task);     }) } 
like image 88
Kris Kowal Avatar answered Nov 02 '22 08:11

Kris Kowal


Any errors that are thrown within the promise chain will cause the entire stack to be aborted early and control is given to the error-back path. (in this case, the fail() handler) When you detect a certain state which causes you to want to abort the promise chain, then just throw a very specific error, which you trap in the error-back and ignore (if you so choose)

function doTask(task, callback) {     Q.ncall(task.step1, task)     .then(function(result1){         if(result1 == 'some failure state I want to cause abortion')         {// the rest of the task chain is unnecessary              console.log('aborting!');             throw new Error('abort promise chain');             return null;         }         return Q.ncall(task.step2, task);     })     .then(function(result2){         console.log('doing step 3...');         return Q.ncall(task.step3, task);     })     .fail(function(err) {         if (err.message === 'abort promise chain') {             // just swallow error because chain was intentionally aborted         }         else {             // else let the error bubble up because it's coming from somewhere else             throw err;         }      })     .end(); } 
like image 45
Calvin Alvin Avatar answered Nov 02 '22 07:11

Calvin Alvin