Можем ли мы делать real-time приложения на Node.js?nodejs-63

Объект Error в Node.js содержит несколько важных полей, каждое из которых служит определенной цели для отладки и обработки ошибок. Разберем каждое из них подробно.

1. error.message

Назначение: Человекочитаемое описание ошибки.

try {
  throw new Error('Файл не найден');
} catch (err) {
  console.log(err.message); // "Файл не найден"
}

Особенности:

  • Первый аргумент конструктора Error
  • Всегда должен быть понятным для разработчика
  • Не предназначен для показа конечным пользователям

2. error.code

Назначение: Машинно-читаемый идентификатор ошибки.

const fs = require('fs');

fs.readFile('несуществующий-файл', (err) => {
  console.log(err.code); // "ENOENT"
});

Типичные коды в Node.js:

  • ENOENT - файл или директория не существует
  • ECONNREFUSED - соединение отклонено
  • ERR_INVALID_ARG_TYPE - неверный тип аргумента

Преимущества:

  • Позволяет программно обрабатывать разные типы ошибок
  • Стандартизирован для встроенных модулей Node.js
  • Можно использовать для локализации сообщений

3. error.stack

Назначение: Трассировка стека вызовов до момента создания ошибки.

function a() { b(); }
function b() { c(); }
function c() { throw new Error('Ошибка!'); }

try {
  a();
} catch (err) {
  console.log(err.stack);
}

Вывод будет содержать:

  • Сообщение ошибки
  • Файл и номер строки для каждого уровня стека
  • Последовательность вызовов функций

Особенности:

  • Формат может отличаться в разных версиях Node.js
  • Может быть отключен для повышения производительности
  • Не следует показывать пользователям (информация безопасности)

4. error.cause

Назначение: Ссылка на оригинальную ошибку при цепочке ошибок.

async function fetchData() {
  try {
    await fetch('https://api.example.com');
  } catch (err) {
    throw new Error('Не удалось загрузить данные', { cause: err });
  }
}

try {
  await fetchData();
} catch (err) {
  console.log('Ошибка:', err.message);
  console.log('Причина:', err.cause.message);
}

Преимущества:

  • Сохраняет контекст ошибки
  • Позволяет строить цепочки ошибок
  • Особенно полезен для асинхронных операций

Практическое применение полей

Обработка ошибок с учетом кода

fs.readFile('config.json', (err, data) => {
  if (err) {
    if (err.code === 'ENOENT') {
      // Создать файл с настройками по умолчанию
    } else if (err.code === 'EACCES') {
      // Ошибка прав доступа
    } else {
      // Неизвестная ошибка
    }
  }
});

Логирование с полной информацией

app.use((err, req, res, next) => {
  logger.error({
    message: err.message,
    code: err.code,
    stack: err.stack,
    cause: err.cause
  });
  res.status(500).send('Internal Server Error');
});

Создание кастомных ошибок

class DatabaseError extends Error {
  constructor(message, query) {
    super(message);
    this.code = 'DB_QUERY_ERROR';
    this.query = query;
  }
}

try {
  throw new DatabaseError('Invalid query', 'SELECT * FROM non_existing');
} catch (err) {
  console.log(err instanceof DatabaseError); // true
  console.log(err.code); // "DB_QUERY_ERROR"
}

Сравнение полей

Характеристика Встроенные объекты Хост-объекты Пользовательские объекты
ИсточникСпецификация JavaScriptСреда выполненияКод разработчика
ПоведениеСтандартизированоЗависит от окруженияОпределяется разработчиком
РасширяемостьДаЧастичноДа
ПримерыArray, Datewindow, documentЛюбые созданные объекты

Резюмируем:

Каждое поле объекта Error в Node.js решает свою задачу. message описывает проблему, code идентифицирует тип ошибки программно, stack помогает в отладке, а cause сохраняет контекст при цепочке ошибок. Правильное использование этих полей значительно улучшает обработку и диагностику ошибок в приложениях.