Обработка асинхронных исключений с помощью bluebird promises
Каков наилучший способ справиться с этим сценарием. Я в контролируемой среде, и я не хочу сбой.
var Promise = require('bluebird');
function getPromise(){
return new Promise(function(done, reject){
setTimeout(function(){
throw new Error("AJAJAJA");
}, 500);
});
}
var p = getPromise();
p.then(function(){
console.log("Yay");
}).error(function(e){
console.log("Rejected",e);
}).catch(Error, function(e){
console.log("Error",e);
}).catch(function(e){
console.log("Unknown", e);
});
Когда вы выбрасываете из setTimeout, мы всегда получаем:
$ node bluebird.js
c:\blp\rplus\bbcode\scratchboard\bluebird.js:6
throw new Error("AJAJAJA");
^
Error: AJAJAJA
at null._onTimeout (c:\blp\rplus\bbcode\scratchboard\bluebird.js:6:23)
at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)
Если бросок происходит до того, как setTimeout поймает bluebirds, он поднимет его:
var Promise = require('bluebird');
function getPromise(){
return new Promise(function(done, reject){
throw new Error("Oh no!");
setTimeout(function(){
console.log("hihihihi")
}, 500);
});
}
var p = getPromise();
p.then(function(){
console.log("Yay");
}).error(function(e){
console.log("Rejected",e);
}).catch(Error, function(e){
console.log("Error",e);
}).catch(function(e){
console.log("Unknown", e);
});
Результаты в:
$ node bluebird.js
Error [Error: Oh no!]
Это здорово - но как бы обрабатывать асинхронный обратный вызов такого типа в node или в браузере.
Ответы
Ответ 1
Promises не домены, они не будут перехватывать исключения из асинхронных обратных вызовов. Вы просто не можете этого сделать.
Promises, однако, улавливают исключения, которые выбрасываются из обратного вызова конструктора then
/catch
/Promise
. Поэтому используйте
function getPromise(){
return new Promise(function(done, reject){
setTimeout(done, 500);
}).then(function() {
console.log("hihihihi");
throw new Error("Oh no!");
});
}
(или просто Promise.delay
), чтобы получить желаемое поведение. Никогда не бросайте пользовательские (безоговорочные) асинхронные обратные вызовы, всегда отказывайтесь от окружающего обещания. Используйте try-catch
, если это действительно необходимо.
Ответ 2
Спасибо @Bergi. Теперь я знаю, что обещание не ломает ошибки в асинхронном обратном вызове. Вот мои 3 примера, которые я тестировал.
Примечание. После отклонения вызова функция продолжит работу.
Пример 1: отклонить, а затем выбросить ошибку в обратном вызове конструктора обещаний
Пример 2: отклонить, а затем выбросить ошибку в callback от асинхронного вызова setTimeout
Пример 3: отклонить, а затем вернуться в обратном вызове asThout setTimeout, чтобы избежать сбоя
// Caught
// only error 1 is sent
// error 2 is reached but not send reject again
new Promise((resolve, reject) => {
reject("error 1"); // Send reject
console.log("Continue"); // Print
throw new Error("error 2"); // Nothing happen
})
.then(() => {})
.catch(err => {
console.log("Error", err);
});
// Uncaught
// error due to throw new Error() in setTimeout async callback
// solution: return after reject
new Promise((resolve, reject) => {
setTimeout(() => {
reject("error 1"); // Send reject
console.log("Continue"); // Print
throw new Error("error 2"); // Did run and cause Uncaught error
}, 0);
})
.then(data => {})
.catch(err => {
console.log("Error", err);
});
// Caught
// Only error 1 is sent
// error 2 cannot be reached but can cause potential uncaught error if err = null
new Promise((resolve, reject) => {
setTimeout(() => {
const err = "error 1";
if (err) {
reject(err); // Send reject
console.log("Continue"); // Did print
return;
}
throw new Error("error 2"); // Potential Uncaught error if err = null
}, 0);
})
.then(data => {})
.catch(err => {
console.log("Error", err);
});