How to properly abort a node.js promise chain using Q?
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); })}
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();}
I believe you only have to reject the promise to break out of the promise chain.
https://github.com/kriskowal/q/wiki/API-Reference#qrejectreason
also it seems like .end() has been changed to .done()
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!'); // by calling Q.reject, your second .then is skipped, // only the .fail is executed. // result1 will be passed to your callback in the .fail call return Q.reject(result1); } return Q.ncall(task.step2, task); }) .then(function(result2){ console.log('doing step 3...'); return Q.ncall(task.step3, task); }) .fail(callback).done();}