
Node.js как серверная платформа приобрела огромную популярность, и, помимо всех технических преимуществ, которые он предоставляет, я лично считаю, что именно простота, с которой мы достигаем намного большего с меньшими затратами, дает ему преимущество.
В этой статье я хотел бы затронуть часто упускаемую из виду тему класса ошибок в Node.js. По моему опыту в качестве обозревателя кода Node.js, я видел, как даже опытные разработчики совершали тривиальные ошибки при выдаче ошибки.
function breakPromise() {
return new Promise((resolve, reject) => {
reject('something');
});
}
breakPromise()
.catch(e => {
console.log(e);
});
--------------------------
Result of console.log
something
Рассмотрим приведенный выше фрагмент кода. Мы отклоняем обещание, использующее строку. Оператор console.log в блоке catch просто напечатает ‘something’. Представьте, что вы будете делать, если вам будет поручено исправить ошибку, которая просто выводит такие строки в журнал.

Мы можем довольно легко исправить эту ситуацию, отклонив / выбросив экземпляры класса Error.
function breakPromiseSmart() {
return new Promise((resolve, reject) => {
reject(new Error('something bad'));
});
}
breakPromiseSmart()
.catch(e => {
console.log(e);
});
-----------------------------
Result of console.log
Error: something bad
at Promise (index.js:3:16)
at new Promise (<anonymous>)
at breakPromiseSmart (index.js:2:12)
at Object.<anonymous> (index.js:7:1)
at Module._compile (module.js:652:30)
at Object.Module._extensions..js (module.js:663:10)
at Module.load (module.js:565:32)
at tryModuleLoad (module.js:505:12)
at Function.Module._load (module.js:497:3)
at Function.Module.runMain (module.js:693:10)
Ясно, что теперь у нас есть гораздо больше информации, с которой можно работать, и поэтому мы никогда не должны выдавать строковые ошибки.
Ошибки, возникающие в node.js, наследуются от стандартного класса Error Javascript или являются его экземплярами.
Класс ошибки предоставляет некоторые полезные свойства, например
- сообщение (сообщение об ошибке)
- name (название ошибки)
- стек (имя файла, номер строки, стек вызовов функции)
Мы можем сделать наши журналы ошибок намного более полезными, добавив свойства к объектам ошибок, однако лучший способ сделать это - создать собственные классы ошибок, расширив класс Error.
class BadRequestError extends Error {
constructor(message, meta = {}) {
super(message);
Error.captureStackTrace(this, BadRequestError);
let proto = Object.getPrototypeOf(this);
proto.name = 'BadRequestError';
this.meta = meta;
}
toString() {
return `${super.toString()} ${JSON.stringify(this.meta)}`;
}
}
function breakPromise() {
return new Promise((resolve, reject) => {
reject(new BadRequestError('something bad', {
expected: 'this',
got: 'that'
}));
});
}
breakPromise()
.catch(e => {
console.log(e);
});
--------------------------------
Result of console.log
{ BadRequestError: something bad
at Promise (index.js:23:16)
at new Promise (<anonymous>)
at breakPromise (index.js:22:12)
at Object.<anonymous> (index.js:30:1)
at Module._compile (module.js:652:30)
at Object.Module._extensions..js (module.js:663:10)
at Module.load (module.js:565:32)
at tryModuleLoad (module.js:505:12)
at Function.Module._load (module.js:497:3)
at Function.Module.runMain (module.js:693:10) meta: { expected: 'this', got: 'that' } }
Мы видим, что, расширив класс Error для создания BadRequestError, мы смогли добавить гораздо больше информации в трассировку стека и обогатить наши журналы.
Заявление Ошибка .captureStackTrace (this, BadRequestError); Короче говоря, используется для исключения конструктора из трассировки стека.
Если мы создадим несколько таких классов ошибок и выбросим их соответствующим образом, мы сможем вернуть правильные ответы. Например
breakPromise()
.catch(e => {
if (e instanceof BadRequestError) {
res.status(400);
} else if (e instanceof SomeotherError) {
res.status(412);
} else {
res.status(500);
}
return res.send({
message: e.message,
error: e.meta
});
});
Все, что я упомянул в посте, очень тривиально, если вам небезразличны ошибки, но поверьте мне, не многие разработчики обращают на это пристальное внимание. Я надеюсь, что после этого освежения вы будете в первую очередь думать о том, чтобы отдавать первоклассное предпочтение ошибкам.
Заявление об ограничении ответственности: не обращайте внимания на некоторые утверждения, в которых я сделал слишком простые обобщения.
Полезные ссылки: