Как правильно прервать цепочку обещаний node.js, используя Q?
Я использую модуль Q для Node.js в попытках избежать "пирамиды обречения" в сценариях, где у меня много шагов. Например:
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();
}
По существу это, похоже, работает; если ошибка вызывается каким-либо из шагов задачи, она передается обратному вызову (хотя я был бы рад усовершенствованиям, так как я новичок в Node.js promises). Однако у меня есть проблема, когда мне нужно прервать цепочку задач раньше. Например, если результат1 успешно возвращен, я могу захотеть вызвать обратный вызов раньше и прервать остальные, но мои попытки сделать это не сработают...
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();
}
В этом примере я вижу как "прерывание!" и "сделать шаг 3...".
Я уверен, что я просто неправильно понимаю некоторые основные принципы здесь, поэтому буду признателен за любую помощь. Спасибо!
Ответы
Ответ 1
Любые ошибки, возникающие в цепочке обещаний, приведут к тому, что весь стек будет прерван раньше, и управление будет передано пути ошибки. (в этом случае обработчик fail()) Когда вы обнаруживаете определенное состояние, из-за которого вы хотите прервать цепочку обещаний, просто введите очень специфическую ошибку, в которую вы попадаете в обратную ошибку и игнорируете (если вы так выбрать)
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 coming from somewhere else
throw err;
}
})
.end();
}
Ответ 2
Это случай, когда вам нужно разветкиться, что означает либо вложение, либо создание подпрограммы.
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)
}
или
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);
})
}
Ответ 3
Я считаю, что вам нужно отказаться только от обещания вырваться из цепочки обещаний.
https://github.com/kriskowal/q/wiki/API-Reference#qrejectreason
также кажется, что .end() был изменен на .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();
}