Try something like this:
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);
});
Instead of:
return bluebird.reject('some reason');
you can use:
throw 'some reason';
and the result would be the same but you didn't want to throw errors so you can return a rejected promise instead.
Update 1
But if your intention is to run all 3 methods in series then you will also need to return the next promise at each step with something like this:
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);
});
Currently the code in your question would never run any other method than the first one.
Update 2
Another example that doesn't call the last catch
for that case:
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);
});
Explanation
Think of it this way: in synchronous code if you had:
r1 = fun1();
r2 = fun2();
r3 = fun3();
then the only way for fun1 to cancel the execution of fun2 and fun3 would be to throw an exception. And similarly for promises, the only way that one then
handler could cancel the execution of the next then
handler is to return a rejected promise. And just like with synchronous code that thrown exception would be caught by the catch
block, here that rejected promise would be passed to the catch
handler.
With synchronous code you can have an internal try/catch
that catches the exception and rethrows it if it isn't the specific one that you used to cancel your execution. With promises you can have an earlier catch
handler that does essentially the same.
This is what happens with the code in Update 2. The rejection reason is compared to some value (which is 'some reason'
in that example) and if it is equal then a resolved promise is returned and so the next catch
handler is not called. If it is not equal then the rejection reason is returned again as a rejected promise witch is then passed to the next catch
handler as a "real" error that you want that last catch
handler to handle.