1. try/catch
try/catchВ основном самые распространенныеasync/awaitПри совместном использовании, в основном, мы будем использовать его для окружения большинства асинхронных методов.awaitпосле ключевого словаpromiseоднаждыreject, ошибка исключения будет брошена.
run();
async function run() {
try {
await Promise.ject(new Error('Oops!'));
} catch (err) {
console.error(error.message);
}
}
try/catchОн также может обрабатывать синхронные ошибки, такие как следующие
:
async function run() {
const v = null;
try {
await Promise.resolve('foo');
v.thisWillThrow;
} catch (error) {
// 会出现"TypeError: Cannot read property 'thisWillThrow' of null"
console.error(error.message);
}
}
returnвопрос
Вроде бы надо только всю логику в мозг засунутьtry/catchТам все хорошо? Не очень точно, но следующий код приведет кunhandled promise rejection. этоreturnКлючевое слово возвращается напрямую, и ошибка не обнаруживается:
async function run() {
try {
// 直接返回Promise,而不是用await关键字
return Promise.reject(new Error('Oops!'));
} catch (error) {
console.error(error.message);
}
}
Решение здесь заключается в использованииreturn awaitрешать:
async function run() {
try {
return await Promise.reject(new Error('Oops!'));
} catch (error) {
console.error(error.message);
}
}
проблема с обратным вызовом
Другой вопросtry catchФункция обратного вызова не может быть захвачена. try catch работает только в одном контексте выполнения. Вот попытка поймать в обратном вызове, чтобы поймать ошибку:
setTimeout(funciton() {
try {
fn()
} catch (e) {
// handle error
}
})
Это работает, ноtry catchпоявится везде. И двигатель V8 обескураженtry catchиспользуется в функции. пытался раньшеtry catchПеремещен на верхний уровень, чтобы перехватывать ошибки в стеке вызовов, но эта обработка не будет работать для асинхронного кода.
2. Golang-style(then)
стиль golang готов к использованию.then()способ совмещенияpromiseПреобразовать в другой, который обрабатывает ошибкиreject promise. Вы можете использовать что-то вродеif(err)проверить:
async function throwAnError() {
throw new Error('Opps!');
}
async function runAwait() {
let err = await throwAnError();
if (err){
console.error(err.message);
}
}
Подобная запись вызовет исключение напрямую, потому что этот метод генерирует исключение, но сам по себе метод бесполезен.try/catchзахватывать. Во многих случаях это может произойти, когда мы используем сторонние библиотеки.
тогда () решение
async function runAwait() {
let err = await throwAnError().then(() => null, err => err);
if (err){
console.error(err.message);
}
}
then()Кстати, буду ждатьpromiseусловиеresolveилиrejectЗатем выполните соответствующий обратный вызов, а затем оценитеerrОбъект обрабатывается, поэтому он фактически эквивалентен захвату.
вернуть и ошибку, и значение
async function run() {
let [err, res] = await throwAnError().then(v => [null, v], err => [err, null]);
if (err){
console.error(err.message);
}
console.log(res)
}
результат:
Это можно сделать путем деструктуризации, чтобы вернуть массив, содержащий результат иerrorобъект. Конечно, еслиrejectвернусьnullа такжеerrorОбъекты; и еслиresolvedВозвращает первое из массиваerrorобъектnull, второе - результат.
Преимущества и недостатки
- Преимущества: с этим шаблоном можно обращаться более лаконично, устраняя при этом необходимость писать
catch. - Недостаток 1: это очень повторяющийся и требует оценки каждый раз, когда выполняется асинхронная операция.
errorобъект. - Недостаток 2: Не могу помочь с обработкой
runОшибка синхронизации в методе. Так что этот метод нужно использовать с осторожностью.
3. Поймать
Оба вышеуказанных режима могут обрабатывать асинхронные ошибки, но для обработки ошибок лучше всего добавить в конце асинхронной логикиcatch, что гарантирует отлов всех ошибок. На самом деле, это также принцип, которыйОбрабатывайте ошибки единообразно, а не оценивайте и обрабатывайте каждую ошибку по отдельности..
async function run() {
return Promise.reject(new Error('Oops!'));
}
run().catch(function handleError(err) {
console.error(err.message);
}).catch( err => {
process.nextTick(() => { throw errl});
})
использоватьcatchпоймать ошибку, еслиhandleErrorОшибки есть и в самих себе, и надо пере-catchснова, но во избежание回调地狱, который завершает процесс, если в методе возникает ошибка.
Преимущества и недостатки
- использовать
catchЕсли это так, он перехватит асинхронную ошибку независимо от того, перехватывает ли ее сам асинхронный метод. - использовать
try/catchНеизбежныйcatchВыдает исключение само по себе, и если оно выдает, оно вложено еще на один уровеньtry/catchКроме того, лучше всего добавитьcatchсделать код более лаконичным.
4 Глобальный захват ошибок
4.1 Захват глобальных ошибок браузера
Глобальная обработка браузера в основном зависит от событий, потому что браузеры управляются событиями. Как только выдается ошибка, интерпретатор останавливает выполнение и расширяется в контексте среды выполнения, после чего будетonerrorГлобальное событие вызывает:
window.addEventListener('error', function (e) {
var error = e.error;
console.log(error);
})
Глобальный обработчик ошибок перехватывает любую ошибку, возникающую в среде выполнения, даже если это ошибка другого объекта или различные типы ошибок. Это распространенный способ обработки ошибок глобально и централизованно.
стек вызовов
Стек вызовов очень важен для обнаружения проблем, и мы можем использовать стек вызовов для обработки определенных ошибок в процессоре.
window.addEventListener('error', function (e) {
var stack = e.error.stack;
var message = e.error.toString();
if (stack) {
message += '\n' + stack;
}
var xhr = new XMLHttpRequest();
xhr.open('POST', '/log', true);
// Fire an Ajax request with error details
xhr.send(message);
});
По логу видно, что именно вызывает какую ошибку. Стек вызовов также может быть очень полезен при отладке. Вы можете проанализировать журнал и посмотреть, какие условия вызывают ошибку.
Уведомление:
Вы не увидите ошибку при междоменном сценарии. В JS сообщения об ошибках разрешены только в том же домене.
личная идея
Чаще всего код выдает исключение. Нас больше волнует, какое значение переменной имеет значение во время выполнения, и не вызывает ли значение этой переменной ошибку, поэтому важнее распечатать больше информации во время выполнения. вызов.
4.2 Глобальный захват ошибок Node.js
Обработка исключений в Node.js сама по себе намного сложнее, поскольку включает в себя процесс или поток, создающий исключение.
Глобальная обработка ошибок на основе Koa
nodejs этоerror-firstМеханизм асинхронной обработки , где нижний уровень будет вызыватьnetмодульныйlistenметод и выполнить обратный вызов при возникновении ошибки.
app.listen(app.config.listenPort, (err) => {
if (err) throw err
app.logger.info(`> Ready on http://localhost:${app.config.listenPort}`)
})
обработка ошибок маршрутизации
Для каждого маршрута также может быть разная логика обработки ошибок.В этом случае входящий запрос от маршрута должен возвращать разные коды исключений и информацию в зависимости от ситуации.
router.get('/loginAuth', async (ctx, next) => {
try {
const code = query.code
const res = await requestToken(code)
if (res.data.code !== 0) {
ctx.app.logger.error(`request token error.Code is ${res.data.code} || response is: ${JSON.stringify(res.data.data)} || msg: ${res.data.message}`)
ctx.body = {
code: 10000,
message: `request token by code error`
}
} else {
ctx.body = res.data
}
} catch (err) {
ctx.app.logger.error(`request api has exception ${ctx.request.url} || ${err.code} || ${err.message} || ${err.stack}`)
ctx.body = {
code: 500,
message: `Error response`
}
}
})
5. Резюме
- Однако часто можно ожидать или превысить исключения, используйте
try/catchнет проблем. - Для непредвиденных ошибок попробуйте использовать
catchчтобы убедиться, что они будут пойманы. - добавить обработчик ошибок в
windowобъект, он будет ловить асинхронные ошибки, соответствующиеDRYа такжеSOLIDв общем. Глобальный обработчик ошибок может помочь вам поддерживать чистоту асинхронного кода.