Модуль Domain в Node.js
Модуль Domain — это инструмент в Node.js для упрощения обработки ошибок в асинхронном коде. Он позволяет объединять несколько асинхронных операций в "domain" и единообразно перехватывать и обрабатывать ошибки внутри этого домена.
Проще говоря, Domain — это как "контейнер" для обработки ошибок. Вы можете поместить связанные асинхронные операции в этот контейнер, а затем централизованно управлять ошибками, которые могут возникнуть в этих операциях.
Использование модуля domain устарело в Node.js 14, потому что сообщество Node.js рекомендует более современные способы обработки ошибок, такие как использование async/await или более комплексная логика прослушивания и обработки ошибок.
Зачем нужен модуль Domain?
В асинхронном программировании Node.js обработка ошибок может стать сложной:
- Асинхронные ошибки трудно перехватить: Традиционный try-catch не может перехватывать ошибки в асинхронных обратных вызовах
- Распространение ошибок затруднено: Ошибки могут возникать в любой асинхронной операции, что затрудняет отслеживание источника
- Проблемы очистки ресурсов: После возникновения ошибки необходимо обеспечить правильное освобождение ресурсов
Модуль Domain предназначен для решения этих проблем.
Основные концепции модуля Domain
1. Создание Domain
Пример
const myDomain = domain.create();
2. Жизненный цикл Domain
- Создание: Используйте
domain.create() - Вход: Используйте
domain.enter()или неявно войти - Run: Выполнить код внутри домена
- Exit: Используйте
domain.exit() - Уничтожение: Автоматически уничтожается, когда нет ссылок
3. Неявное связывание
Domain может быть неявно привязан к следующим объектам:
setTimeout/setIntervalОбратные вызовы- События EventEmitter
- Операции с потоками
Основные методы Domain
1. domain.run(fn)
Выполните функцию в контексте домена:
Пример
// Асинхронные операции здесь будут перехвачены доменом
setTimeout(() => {
throw new Error('Асинхронная ошибка');
}, 100);
});
2. domain.add(emitter)
Явно добавьте экземпляр EventEmitter в домен:
Пример
myDomain.add(server);
3. domain.remove(emitter)
Удалите экземпляр EventEmitter из домена.
4. domain.bind(callback)
Возвращает новую функцию, привязанную к домену:
Пример
if (err) throw err;
console.log(data);
});
5. domain.intercept(callback)
Подобно bind, но специально обрабатывает колбэки с ошибкой в первом аргументе:
Пример
console.log(data);
});
Обработка ошибок
Domain обрабатывает перехваченные ошибки черезerrorсобытие error:
Пример
console.error('Domain перехватил ошибку:', err);
// Освободить ресурсы
server.close();
});
Практические примеры применения
1. Обработка ошибок HTTP-сервера
Пример
const domain = require('domain');
const server = http.createServer((req, res) => {
const d = domain.create();
d.on('error', (err) => {
res.statusCode = 500;
res.end(`Ошибка сервера: ${err.message}`);
// Предотвратить сбой процесса
server.close();
});
d.run(() => {
// Обработать запрос
process.nextTick(() => {
// Имитировать асинхронную ошибку
if (req.url === '/error') {
throw new Error('Intentional error');
}
res.end('OK');
});
});
});
server.listen(3000);
2. Управление соединениями с базой данных
Пример
const db = require('some-db-library');
function queryDatabase(callback) {
const d = domain.create();
d.on('error', (err) => {
console.error('Ошибка базы данных:', err);
db.releaseConnection();
});
d.run(() => {
db.getConnection((err, connection) => {
if (err) throw err;
connection.query('SELECT * FROM users', (err, results) => {
if (err) throw err;
callback(null, results);
db.releaseConnection();
});
});
});
}
Ограничения Domain
- Устарело: Node.js официально объявил модуль domain устаревшим; рекомендуется использовать async_hooks или другие методы
- Утечки памяти: Неправильное использование может привести к утечкам памяти
- Накладные расходы производительности: Создание и управление доменами связано с некоторыми накладными расходами производительности
Альтернативы
Поскольку модуль domain устарел, рассмотрите следующие альтернативы:
- async/await + try-catch: Используйте современные методы асинхронной обработки JavaScript
- Обработка ошибок Promise: Используйте
.catch()для обработки ошибок в цепочках Promise - async_hooks: Низкоуровневый API отслеживания асинхронного контекста, предоставляемый Node.js
Методы и свойства
| Метод/Свойство | Описание |
|---|---|
domain.create() | Создать и вернуть новыйdomainэкземпляр. |
domain.run(callback) | Запустить предоставленную функцию обратного вызова в домене, автоматически перехватывая ошибки внутри обратного вызова. |
domain.bind(callback) | Создать новую функцию, которая вызывает исходную функцию, перехватывая любые выброшенные ошибки. |
domain.intercept(callback) | Похоже наbind(), но передаёт ошибку в качестве первого аргумента функции обратного вызова. |
domain.add(emitter) | Явно добавить объект EventEmitter или Timer, чтобы его ошибки перехватывались текущим доменом. |
domain.remove(emitter) | Удалить указанный объект EventEmitter или Timer из домена. |
domain.on('error', callback) | Прослушивать событие доменаerror, перехватывая все необработанные ошибки. |
Пример
1. Создать домен и использовать domain.run() для перехвата ошибок
domain.run() может помещать асинхронные операции в домен; если в операции возникает ошибка, она будет перехвачена и обработана текущим доменом.
Пример
const d = domain.create();
d.on('error', (err) => {
console.log('Caught error:', err);
});
d.run(() => {
setTimeout(() => {
throw new Error('Asynchronous error');
}, 100);
});
В приведённом выше примере ошибка в setTimeout перехватывается событием error домена d, не вызывая падения процесса.
2. Используйте domain.bind() для перехвата ошибок в колбэках
domain.bind() создаёт функцию-обёртку, которая может перехватывать ошибки из callback-функции в текущий домен.
Пример
const d = domain.create();
d.on('error', (err) => {
console.log('Caught error:', err);
});
const asyncFunction = d.bind((callback) => {
setTimeout(() => {
callback(new Error('Error in callback'));
}, 100);
});
asyncFunction((err) => {
if (err) throw err;
});
Здесь ошибка в asyncFunction будет перехвачена и обработана доменом.
3. Используйте domain.add() для явного добавления событий
Вы можете использовать domain.add(), чтобы добавить конкретный EventEmitter в домен, так что его ошибки также будут перехватываться доменом.
Пример
const EventEmitter = require('events');
const d = domain.create();
const emitter = new EventEmitter();
d.on('error', (err) => {
console.log('Caught EventEmitter error:', err);
});
// Добавить emitter в domain
d.add(emitter);
emitter.on('data', () => {
throw new Error('Error in EventEmitter');
});
emitter.emit('data');
Когда событие data выбрасывает ошибку, domain перехватывает эту ошибку, не приводя к сбою программы.
Примечания и ограничения domain
- Влияние на производительность:
domainЭто будет оказывать определённое влияние на производительность, особенно в сценариях с высокой конкурентностью, поэтому частое использование не рекомендуется. - Не рекомендуется использовать в новых проектах: начиная с Node.js 4.0,
domainбыл помечен как устаревший модуль. В новых проектах рекомендуется использовать более современные методы обработки ошибок, такие какasync/await、try/catchи прослушиватели событий и т. д. - Не подходит для всех сценариев:
domainОн не может перехватывать все типы ошибок (например, синтаксические ошибки); он подходит только для обработки ошибок времени выполнения в асинхронных операциях и функциях обратного вызова.
Альтернативы
Посколькуdomainбыл объявлен устаревшим, рекомендуется использовать следующие способы обработки ошибок в асинхронных операциях:
- Используйте
async/awaitиtry/catch: Для функций, поддерживающих async/await, ошибки можно перехватывать с помощьюtry/catch. - Глобальная обработка ошибок: Можно использовать
process.on('uncaughtException')иprocess.on('unhandledRejection')чтобы прослушивать неперехваченные исключения и необработанные отклонения Promise. - Обработка ошибок для слушателей событий: Добавьте слушатель к каждому EventEmitter
errorсобытие.
ХотяdomainМодуль предоставляет удобный способ перехвата ошибок в асинхронных операциях, но из-за проблем с производительностью и надёжностью Node.js официально не рекомендует использовать его в новых проектах. Для обработки исключений рекомендуется использовать более современные решения, такие какasync/awaitи слушатели событий, чтобы гарантировать, что ошибки могут эффективно обрабатываться в приложении.
Встроенные модули Node.js