Используйте cancel() внутри цепочки then, созданной promisifyAll
Не уверен, что я достаточно ясен с этим названием, но предположим, что у меня есть класс с именем Foo method1
, method2
а также method3
, Я обещаю его методы с promisifyAll
,
Тогда у меня есть цепочка затем, и я хочу отменить операцию в середине секунды или сначала тогда, и далее не следует вызывать.
Я читал об отмене ( http://bluebirdjs.com/docs/api/cancellation.html), но я не знаю, как реализовать это с promisifyAll.
Код, который я получил, плюс то, что мне нужно:
var bluebird = require('bluebird');
function Foo() { }
Foo.prototype.method1 = function (cb) {};
Foo.prototype.method2 = function (cb) {};
Foo.prototype.method3 = function (cb) {};
var foo = bluebird.promisifyAll(new Foo());
foo.method1Async()
.then(function (r1) {
// cancel then-chain
res.json("Task stopped");
// just stop right here
promises.cancel();
})
.then(function (r2) {
console.log(r2);
}).then(function (r3) {
console.log(r3);
})
.catch(function (er) {
console.log('Catch!');
});
Как правильно получить этот результат? Я знаю, что могу просто бросить что-нибудь и поймать это в catch
метод, но это внесет очень большие изменения в моем реальном коде.
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 - это создать исключение. И аналогично для обещаний, единственный способ, которым один then
Обработчик может отменить выполнение следующего then
Обработчик должен вернуть отклоненное обещание. И так же, как в синхронном коде, это исключение будет поймано catch
блок, здесь это отклоненное обещание будет передано catch
обработчик.
С синхронным кодом вы можете иметь внутренний try/catch
это ловит исключение и сбрасывает его, если оно не является тем, которое вы использовали для отмены своего выполнения. С обещаниями вы можете иметь раньше catch
обработчик, который делает по существу то же самое.
Это то, что происходит с кодом в обновлении 2. Причина отклонения сравнивается с некоторым значением (которое 'some reason'
в этом примере), и если оно равно, то возвращается разрешенное обещание, и поэтому следующий catch
обработчик не вызывается. Если она не равна, то причина отказа возвращается снова, поскольку ведьма, получившая отказ, затем передается следующему. catch
обработчик как "настоящая" ошибка, которую вы хотите, чтобы последний catch
обработчик для обработки.