Улавливание ошибок в JavaScript Promises с помощью первого уровня try... catch

Итак, я хочу, чтобы мой захват первого уровня был тем, который обрабатывает ошибку. Есть ли способ распространять мою ошибку до этого первого улова?

Код ссылки, не работает (пока):

Promise = require('./framework/libraries/bluebird.js');

function promise() {
    var promise = new Promise(function(resolve, reject) {
        throw('Oh no!');
    });

    promise.catch(function(error) {
        throw(error);
    });
}

try {   
    promise();
}
// I WANT THIS CATCH TO CATCH THE ERROR THROWN IN THE PROMISE
catch(error) {
    console.log('Caught!', error);
}

Ответы

Ответ 1

С помощью нового синтаксиса async/await вы можете достичь этого. Обратите внимание, что на момент написания это не поддерживается всеми браузерами, вам, вероятно, нужно перевести код babel (или что-то подобное).

// Because of the "async" keyword here, calling getSomeValue()
// will return a promise.
async function getSomeValue() {
  if (somethingIsNotOk) {
    throw new Error('uh oh');
  } else {
    return 'Yay!';
  }
}

async function() {
  try {
    // "await" will wait for the promise to resolve or reject
    // if it rejects, an error will be thrown, which you can
    // catch with a regular try/catch block
    const someValue = await getSomeValue();
    doSomethingWith(someValue);
  } catch (error) {
    console.error(error);
  }
}

Ответ 2

Вы не можете использовать команды try-catch для обработки исключений, созданных асинхронно, поскольку функция "возвращает" до того, как будет выбрано любое исключение. Вместо этого вы должны использовать методы promise.then и promise.catch, которые представляют асинхронный эквивалент оператора try-catch.

Что вам нужно сделать, так это вернуть обещание, а затем связать с ним еще один .catch:

function promise() {
    var promise = new Promise(function(resolve, reject) {
        throw('Oh no!');
    });

    return promise.catch(function(error) {
        throw(error);
    });
}

promise().catch(function(error) {
    console.log('Caught!', error);
});

Promises являются цепями, поэтому, если обещание повторяет ошибку, оно будет делегировано до следующего .catch.

Кстати, вам не нужно использовать круглые скобки вокруг операторов throw (throw a совпадает с throw(a)).


Если вы используете этот код в Node.js, и по какой-то причине вам не разрешено редактировать функцию promise, вы можете использовать домены для этого. Обратите внимание, что домены - это не самые простые вещи, с которыми приходится иметь дело, и в некоторых случаях имеют некоторые досадные краевые случаи. Если вам это действительно нужно, я бы рекомендовал вместо этого использовать promises.

Ответ 3

Нет! Это абсолютно невозможно, так как promises по своей сути асинхронны. Предложение try-catch будет завершено, когда будет выбрано исключение (и путешествие по времени еще не было изобретено).

Вместо этого верните promises из всех ваших функций и зацепите за них обработчик ошибок.

Ответ 4

Я часто нахожу необходимость обеспечить возврат обещания и почти так же часто нужно обрабатывать локальную ошибку, а затем, возможно, повторно ее уничтожить.

function doSomeWork() {
  return Promise.try(function() {

    return request.get(url).then(function(response) {
      // ... do some specific work
    });

  }).catch(function(err) {
    console.log("Some specific work failed", err);
    throw err; // IMPORTANT! throw unless you intend to suppress the error
  });
}

Преимущество этого метода (Promise.try/catch) заключается в том, что вы запускаете/обеспечиваете цепочку Promise без требования разрешения/отклонения, которое легко можно пропустить и создать кошмар для отладки.

Ответ 5

Чтобы расширить на edo ответ, если вы хотите поймать ошибки async-функции, которую вы не хотите ждать. Вы можете добавить выражение ожидания в конце своей функции.

async function() {
  try {
    const asyncResult = someAsyncAction();

    // "await" will wait for the promise to resolve or reject
    // if it rejects, an error will be thrown, which you can
    // catch with a regular try/catch block
    const someValue = await getSomeValue();
    doSomethingWith(someValue);

    await asyncResult;
  } catch (error) {
    console.error(error);
  }
}

Если someAsyncAction не работает, оператор catch будет обрабатывать его.