Node.js
Обработка исключений
Поиск…
Исправление обработки в Node.Js
Node.js имеет 3 основных способа обработки исключений / ошибок:
- блок try- catch
- ошибка в качестве первого аргумента для
callback
-
emit
событие ошибки с помощью eventEmitter
try-catch используется для обнаружения исключений, возникающих при выполнении синхронного кода. Если вызывающий (или вызывающий абонент, ...) использовал try / catch, то они могут поймать ошибку. Если ни один из вызывающих абонентов не имеет попыток, чем программа выйдет из строя.
Если использование try-catch в async-операции и исключение было выбрано из обратного вызова метода async, то оно не попадет в try-catch. Чтобы поймать исключение из обратного вызова асинхронной операции, предпочтительно использовать обещания .
Пример, чтобы лучше понять его
// ** Example - 1 **
function doSomeSynchronousOperation(req, res) {
if(req.body.username === ''){
throw new Error('User Name cannot be empty');
}
return true;
}
// calling the method above
try {
// synchronous code
doSomeSynchronousOperation(req, res)
catch(e) {
//exception handled here
console.log(e.message);
}
// ** Example - 2 **
function doSomeAsynchronousOperation(req, res, cb) {
// imitating async operation
return setTimeout(function(){
cb(null, []);
},1000);
}
try {
// asynchronous code
doSomeAsynchronousOperation(req, res, function(err, rs){
throw new Error("async operation exception");
})
} catch(e) {
// Exception will not get handled here
console.log(e.message);
}
// The exception is unhandled and hence will cause application to break
обратные вызовы в основном используются в Node.js, поскольку обратный вызов выполняет асинхронное событие. Пользователь передает вам функцию (обратный вызов), и вы вызываете ее когда-нибудь позже, когда асинхронная операция завершается.
Обычная модель заключается в том, что обратный вызов вызывается как обратный вызов (ошибка, результат) , где только один из ошибок и результатов не равен нулю, в зависимости от того, была ли операция успешной или неудачной.
function doSomeAsynchronousOperation(req, res, callback) {
setTimeout(function(){
return callback(new Error('User Name cannot be empty'));
}, 1000);
return true;
}
doSomeAsynchronousOperation(req, res, function(err, result) {
if (err) {
//exception handled here
console.log(err.message);
}
//do some stuff with valid data
});
emit Для более сложных случаев вместо использования обратного вызова сама функция может возвращать объект EventEmitter, и ожидается, что вызывающий абонент будет прослушивать события ошибки на эмиттере.
const EventEmitter = require('events');
function doSomeAsynchronousOperation(req, res) {
let myEvent = new EventEmitter();
// runs asynchronously
setTimeout(function(){
myEvent.emit('error', new Error('User Name cannot be empty'));
}, 1000);
return myEvent;
}
// Invoke the function
let event = doSomeAsynchronousOperation(req, res);
event.on('error', function(err) {
console.log(err);
});
event.on('done', function(result) {
console.log(result); // true
});
Управление незатронутыми исключениями
Поскольку Node.js работает на одном процессе, неработающие исключения - это проблема, о которой следует знать при разработке приложений.
Без исключения
Большинство людей позволяют серверу (узлам) node.js незаметно проглатывать ошибки.
- Тишина обработки исключения
process.on('uncaughtException', function (err) {
console.log(err);
});
Это плохо , он будет работать, но:
Корневая причина остается неизвестной, так как это не будет способствовать разрешению того, что вызвало исключение (ошибка).
В случае, если соединение с базой данных (пул) закрывается по какой-либо причине, это приведет к постоянному распространению ошибок, что означает, что сервер будет работать, но он не будет повторно подключаться к db.
Возврат в начальное состояние
В случае «uncaughtException» хорошо перезапустить сервер и вернуть его в исходное состояние , где мы знаем, что он будет работать. Исключение регистрируется, приложение завершается, но поскольку он будет запущен в контейнере, который будет следить за тем, чтобы сервер работал, мы достигнем перезапуска сервера (вернемся к исходному рабочему состоянию).
- Установка вечно (или другого инструмента CLI, чтобы убедиться, что сервер узла работает непрерывно)
npm install forever -g
- Запуск сервера навсегда
forever start app.js
Причина, почему она началась и почему мы используем вечно, - это то, что сервер будет завершен навсегда, и процесс снова запустит сервер.
- Перезапуск сервера
process.on('uncaughtException', function (err) {
console.log(err);
// some logging mechanisam
// ....
process.exit(1); // terminates process
});
На стороне заметки был также способ обработки исключений с кластерами и доменами .
Домены больше не рекомендуют здесь .
Ошибки и обещания
Обещания обрабатывают ошибки по-разному для синхронного или обратного кода.
const p = new Promise(function (resolve, reject) {
reject(new Error('Oops'));
});
// anything that is `reject`ed inside a promise will be available through catch
// while a promise is rejected, `.then` will not be called
p
.then(() => {
console.log("won't be called");
})
.catch(e => {
console.log(e.message); // output: Oops
})
// once the error is caught, execution flow resumes
.then(() => {
console.log('hello!'); // output: hello!
});
в настоящее время ошибки, сбрасываемые в обещание, которое не попало, приводят к проглатыванию ошибки, что может затруднить отслеживание ошибки. Это можно решить, используя инструменты linting, такие как eslint, или гарантируя, что вы всегда имеете предложение catch
.
Это поведение устарело в узле 8 в пользу прекращения процесса узла.