I'm under the impression that an exception inside a promise will trigger the subsequent fail-handler, but I'm not seeing it happen in this code:
var Q = require('q');
function x() {
console.log('x');
var deferred = Q.defer();
setTimeout(
function() {
console.log('resolving x');
deferred.resolve('hi');
},
1000
);
return deferred.promise;
}
function y() {
console.log('y');
var deferred = Q.defer();
setTimeout(
function() {
console.log('throwing in y');
throw new Error('Oih!');
},
1000
);
return deferred.promise;
}
x().then(y).then(
function () {
console.log('yes');
},
function () {
console.log('no');
}
);
Am I doing something wrong, or have I misunderstood?
You are mixing callbacks and promises + you have a case of deferred anti-pattern. Either use Q.delay
or a wrapper like:
function delay(ms) {
var d = Q.defer();
setTimeout(d.resolve, ms);
return d.promise;
}
Now that there is promise API for timeouts, there is no reason to use setTimeout:
function x() {
return delay(1000).then(function () {
console.log("hi");
});
}
function y() {
return delay(1000).then(function () {
console.log('throwing in y');
throw new Error('Oih!');
});
}
Use:
x()
.then(y)
.then(function() {
console.log('yes');
})
.catch(function(e) {
console.log('no');
});
All exceptions inside a promise chain are catched. You must either manage a failing promise as you did, or end the promise chain using done()
in order to expose and throw the error (see the documentation).
However, the error you're throwing in the setTimeout
is not related to the promise as the error is thrown asynchronously, see for instance this relevant question. The alternative is to reject the promise like this:
function y() {
console.log('y');
var deferred = Q.defer();
setTimeout(
function() {
console.log('throwing in y');
deferred.reject(new Error('Oih!'));
},
1000
);
return deferred.promise;
}