Spec-Zone.ru › Bluebird

.catch

.catch это удобный метод для обработки ошибок в цепочках промисов. Он существует в двух вариантах - универсальный вариант, похожий на синхронный блок catch(e) {. Этот вариант совместим с нативными промисами. - Фильтрованный вариант (как обычно бывает в других языках, не являющихся JS), который позволяет обрабатывать только определенные ошибки. Этот вариант обычно предпочтительнее и значительно безопаснее.

Примечание по обработке исключений промисов.

Обработка исключений промисов отражает обработку исключений в JavaScript. Синхронная функция throw аналогична отклонению промиса. Вот пример для иллюстрации:

function getItems(param) {
    try { 
        var items = getItemsSync();
        if(!items) throw new InvalidItemsError();  
    } catch(e) { 
        // can address the error here, either from getItemsSync returning a falsey value or throwing itself
        throw e; // need to re-throw the error unless I want it to be considered handled. 
    }
    return process(items);
}

Аналогично, с промисами:

function getItems(param) {
    return getItemsAsync().then(items => {
        if(!items) throw new InvalidItemsError(); 
        return items;
    }).catch(e => {
        // can address the error here and recover from it, from getItemsAsync rejects or returns a falsey value
        throw e; // Need to rethrow unless we actually recovered, just like in the synchronous version
    }).then(process);
}

Универсальный обработчик

.catch(function(any error) handler) -> Promise
.caught(function(any error) handler) -> Promise

Это универсальный обработчик исключений, сокращение для вызова .then(null, handler) на этом промисе. Любое исключение, произошедшее в цепочке .then, будет передано ближайшему обработчику .catch.

Для совместимости с более ранними версиями ECMAScript предоставляется псевдоним .caught для .catch.

Фильтрованный обработчик

.catch(
    class ErrorClass|function(any error)|Object predicate...,
    function(any error) handler
) -> Promise
.caught(
    class ErrorClass|function(any error)|Object predicate...,
    function(any error) handler
) -> Promise

Это расширение для .catch, которое работает больше как операторы catch в языках типа Java или C#. Вместо ручного проверки instanceof или .name === "SomeError", вы можете указать ряд конструкторов ошибок, которые подходят для этого обработчика. Обработчик, который первым встретит подходящие конструкторы, будет вызван.

Пример:

somePromise.then(function() {
    return a.b.c.d();
}).catch(TypeError, function(e) {
    //If it is a TypeError, will end up here because
    //it is a type error to reference property of undefined
}).catch(ReferenceError, function(e) {
    //Will end up here if a was never declared at all
}).catch(function(e) {
    //Generic catch-the rest, error wasn't TypeError nor
    //ReferenceError
});

Вы также можете добавить несколько фильтров для обработчика catch:

somePromise.then(function() {
    return a.b.c.d();
}).catch(TypeError, ReferenceError, function(e) {
    //Will end up here on programmer error
}).catch(NetworkError, TimeoutError, function(e) {
    //Will end up here on expected everyday network errors
}).catch(function(e) {
    //Catch any unexpected errors
});

Чтобы параметр считался типом ошибки, который вы хотите отфильтровать, конструктор должен иметь свойство .prototype равное instanceof Error.

Такой конструктор можно создать следующим образом:

function MyCustomError() {}
MyCustomError.prototype = Object.create(Error.prototype);

Использование:

Promise.resolve().then(function() {
    throw new MyCustomError();
}).catch(MyCustomError, function(e) {
    //will end up here now
});

Однако, если вам нужны трассировки стека и более чистый вывод строк, сделайте следующее:

в Node.js и других средах V8, с поддержкой Error.captureStackTrace

function MyCustomError(message) {
    this.message = message;
    this.name = "MyCustomError";
    Error.captureStackTrace(this, MyCustomError);
}
MyCustomError.prototype = Object.create(Error.prototype);
MyCustomError.prototype.constructor = MyCustomError;

Используя CoffeeScript's class для того же:

class MyCustomError extends Error
  constructor: (@message) ->
    @name = "MyCustomError"
    Error.captureStackTrace(this, MyCustomError)

Этот метод также поддерживает фильтры на основе предикатов. Если вы передаете функцию-предикат вместо конструктора ошибки, предикат получит ошибку в качестве аргумента. Результат выполнения предиката будет использоваться для определения того, следует ли вызывать обработчик ошибки.

Предикаты позволяют очень точно контролировать пойманные ошибки: сопоставление с образцом, наборы типов ошибок с операциями над множествами и многие другие методы могут быть реализованы на их основе.

Пример использования фильтра на основе предиката:

var Promise = require("bluebird");
var request = Promise.promisify(require("request"));

function ClientError(e) {
    return e.code >= 400 && e.code < 500;
}

request("http://www.google.com").then(function(contents) {
    console.log(contents);
}).catch(ClientError, function(e) {
   //A client error like 400 Bad Request happened
});

Функции-предикаты, проверяющие только свойства, имеют удобное сокращение. Вместо функции-предиката вы можете передать объект, и его свойства будут проверяться на соответствие объекту ошибки:

fs.readFileAsync(...)
    .then(...)
    .catch({code: 'ENOENT'}, function(e) {
        console.log("file not found: " + e.path);
    });

Объектный предикат, переданный .catch в приведенном выше коде ({code: 'ENOENT'}), является сокращением для функции-предиката function predicate(e) { return isObject(e) && e.code == 'ENOENT' }, т.е. используется нестрогое равенство.

Для совместимости с более ранними версиями ECMAScript предоставляется псевдоним .caught для .catch.

Не возвращая отклоненное значение или throw из catch, вы "восстанавливаетесь после ошибки" и продолжаете цепочку:

Promise.reject(Error('fail!'))
  .catch(function(e) {
    // fallback with "recover from failure"
    return Promise.resolve('success!'); // promise or value
  })
  .then(function(result) {
    console.log(result); // will print "success!"
  });

Это точно так же, как синхронный код:

var result;
try {
  throw Error('fail');
} catch(e) {
  result = 'success!';
}
console.log(result);

© 2013–2018 Petka Antonov
Licensed under the MIT License.
http://bluebirdjs.com/docs/api/catch.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API