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