.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