Ответ 1
Попробуйте что-то вроде этого:
var bluebird = require('bluebird');
function Foo() { }
Foo.prototype.method1 = function (cb) { cb(null, 'method1'); };
Foo.prototype.method2 = function (cb) { cb(null, 'method2'); };
Foo.prototype.method3 = function (cb) { cb(null, 'method3'); };
var foo = bluebird.promisifyAll(new Foo());
foo.method1Async()
.then(function (r1) {
console.log('step 1');
// cancel then-chain
console.log("Task stopped");
// just stop right here
return bluebird.reject('some reason');
})
.then(function (r2) {
console.log('step 2');
console.log(r2);
}).then(function (r3) {
console.log('step 3');
console.log(r3);
})
.catch(function (er) {
console.log('Catch!');
console.log('Error:', er);
});
Вместо:
return bluebird.reject('some reason');
вы можете использовать:
throw 'some reason';
и результат будет таким же, но вы не захотите вводить ошибки, чтобы вместо этого вы могли вернуть отклоненное обещание.
Обновление 1
Но если вы намерены последовательно запускать все 3 метода, вам также нужно будет вернуть следующее обещание на каждом шаге с помощью следующего:
var bluebird = require('bluebird');
function Foo() { }
Foo.prototype.method1 = function (cb) { cb(null, 'method1'); };
Foo.prototype.method2 = function (cb) { cb(null, 'method2'); };
Foo.prototype.method3 = function (cb) { cb(null, 'method3'); };
var foo = bluebird.promisifyAll(new Foo());
foo.method1Async()
.then(function (r1) {
console.log('step 1');
console.log('got value:', r1);
// cancel? change to true:
var cancel = false;
if (cancel) {
console.log("Task stopped");
return bluebird.reject('some reason');
} else {
console.log('Keep going');
return foo.method2Async();
}
})
.then(function (r2) {
console.log('step 2');
console.log('got value:', r2);
return foo.method3Async();
}).then(function (r3) {
console.log('step 3');
console.log('got value:', r3);
})
.catch(function (er) {
console.log('Catch!');
console.log('Error:', er);
});
В настоящее время код в вашем вопросе никогда не будет запускать какой-либо другой метод, чем первый.
Обновление 2
Другой пример, который не вызывает последний catch
для этого случая:
foo.method1Async()
.then(function (r1) {
console.log('step 1');
console.log('got value:', r1);
// cancel? change to true:
var cancel = true;
if (cancel) {
console.log("Task stopped");
return bluebird.reject('some reason');
} else {
console.log('Keep going');
return foo.method2Async();
}
})
.then(function (r2) {
console.log('step 2');
console.log('got value:', r2);
return foo.method3Async();
}).then(function (r3) {
console.log('step 3');
console.log('got value:', r3);
})
.catch(function (er) {
if (er === 'some reason') {
return bluebird.resolve('ok');
} else {
return bluebird.reject(er);
}
})
.catch(function (er) {
console.log('Catch!');
console.log('Error:', er);
});
Описание
Подумайте об этом так: в синхронном коде, если у вас есть:
r1 = fun1();
r2 = fun2();
r3 = fun3();
тогда единственный способ для fun1 отменить выполнение fun2 и fun3 - это выбросить исключение. Аналогично для promises единственный способ, которым один обработчик then
мог отменить выполнение следующего обработчика then
, - это вернуть отклоненное обещание. И точно так же, как с синхронным кодом, что исключенное исключение будет захвачено блоком catch
, здесь отклоненное обещание будет передано обработчику catch
.
С синхронным кодом у вас может быть внутренний try/catch
, который улавливает исключение и повторяет его, если это не тот, который вы использовали для отмены выполнения. С помощью promises вы можете иметь более ранний обработчик catch
, который делает практически то же самое.
Это то, что происходит с кодом в обновлении 2. Причина отклонения сравнивается с некоторым значением (которое в этом примере равно 'some reason'
), и если оно равно, то возвращается обещанное обещание, и поэтому следующий catch
обработчик не вызывается. Если это не равно, то причина отклонения возвращается снова как отклоненное обещание, которое затем передается следующему обработчику catch
как "реальная" ошибка, которую вы хотите обработать последним обработчиком catch
.