Обработка асинхронных исключений с помощью 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);
  });