Домен¶
Стабильность: 0 – устарело или набрало много негативных отзывов
Эта фича является проблемной и её планируют изменить. Не стоит полагаться на неё. Использование фичи может вызвать ошибки. Не стоит ожидать от неё обратной совместимости.
Этот модуль готовится к удалению. После того как будет готов API-заменитель, модуль будет полностью объявлён устаревшим. Большинству разработчиков не следует им пользоваться. Тем, кому без альтернативы нужна именно функциональность доменов, можно временно на неё опираться, но следует планировать переход на другое решение.
Домены позволяют обрабатывать несколько различных операций ввода-вывода как одну группу. Если один из привязанных к домену эмиттеров событий или обратных вызовов генерирует событие 'error' или выбрасывает ошибку, уведомляется объект домена, а не теряется контекст ошибки в обработчике process.on('uncaughtException') и не происходит немедленный выход процесса с кодом ошибки.
Предупреждение: не игнорируйте ошибки¶
Обработчики ошибок домена не заменяют корректное завершение процесса при ошибке.
Из-за того, как в JavaScript работает throw, почти нельзя безопасно «продолжить с того же места», не допустив утечек ссылок или хрупкого неопределённого состояния.
Самый безопасный ответ на выброшенную ошибку — завершить процесс. В обычном веб-сервере может быть много открытых соединений, и резко обрывать их из-за ошибки, вызванной одним запросом, обычно нельзя.
Лучше отправить ответ об ошибке тому запросу, который её спровоцировал, дать остальным завершиться в обычном режиме и перестать принимать новые запросы в этом воркере.
Так использование domain сочетается с модулем cluster: основной процесс может создать нового воркера, когда в воркере произошла ошибка. В распределённых программах завершающий прокси или реестр сервисов может зафиксировать сбой и отреагировать.
Например, так делать не стоит:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
Сочетая контекст домена и устойчивость к разделению программы на несколько воркеров, можно реагировать адекватнее и безопаснее обрабатывать ошибки.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | |
Дополнительные поля объектов Error¶
Когда объект Error проходит через домен, к нему добавляются поля:
error.domain— домен, который первым обработал ошибку.error.domainEmitter— эмиттер, сгенерировавший событие'error'с этим объектом.error.domainBound— функция обратного вызова, привязанная к домену и получившая ошибку первым аргументом.error.domainThrown— булево значение: ошибка была выброшена, испущена как событие или передана в привязанный колбэк.
Неявное связывание¶
Если домены используются, все новые объекты EventEmitter (включая Stream, запросы, ответы и т.д.) неявно привязываются к активному домену в момент создания.
Кроме того, колбэки для низкоуровневых запросов цикла событий (например fs.open() и других с колбэками) автоматически привязываются к активному домену. Если они выбрасывают исключение, домен перехватывает ошибку.
Чтобы не раздувать память, сами объекты Domain не добавляются неявно дочерними к активному домену — иначе легко помешать сборке мусора для объектов запроса и ответа.
Чтобы вкладывать объекты Domain в родительский Domain, их нужно добавлять явно.
Неявное связывание направляет выброшенные ошибки и события 'error' в событие 'error' домена, но не регистрирует EventEmitter на домене. Неявное связывание обрабатывает только выброшенные ошибки и события 'error.
Явное связывание¶
Иногда активный домен не тот, который нужен конкретному эмиттеру. Или эмиттер создан в одном домене, а должен быть привязан к другому.
Например, для HTTP-сервера можно использовать один домен, а для каждого запроса — отдельный.
Это делается явным связыванием.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | |
domain.create()¶
- Возвращает:
<Domain>
Класс: Domain¶
- Наследует:
<EventEmitter>
Класс Domain инкапсулирует маршрутизацию ошибок и необработанных исключений к активному объекту Domain.
Чтобы обрабатывать перехваченные ошибки, подпишитесь на событие 'error'.
domain.members¶
- Тип:
<Array>
Массив эмиттеров, явно добавленных в домен.
domain.add(emitter)¶
emitter<EventEmitter>эмиттер, добавляемый в домен
Явно добавляет эмиттер в домен. Если обработчики эмиттера выбрасывают ошибку или эмиттер генерирует 'error', это маршрутизируется в 'error' домена, как при неявном связывании.
Если EventEmitter уже был привязан к домену, он отвязывается от того и привязывается к этому.
domain.bind(callback)¶
callback<Function>функция обратного вызова- Возвращает:
<Function>обёрнутая функция
Возвращаемая функция оборачивает переданный колбэк. При её вызове выброшенные ошибки направляются в событие 'error' домена.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
domain.enter()¶
Метод enter() — внутренняя часть реализации run(), bind() и intercept(): задаёт активный домен. Устанавливает domain.active и process.domain на этот домен и помещает домен в стек доменов (см. domain.exit()). Вызов enter() ограничивает начало цепочки асинхронных вызовов и операций ввода-вывода, привязанных к домену.
enter() меняет только активный домен, не сам объект домена. enter() и exit() можно вызывать произвольное число раз для одного домена.
domain.exit()¶
Метод exit() выходит из текущего домена, снимая его со стека. При переключении на другую цепочку асинхронных вызовов важно выйти из текущего домена. Вызов exit() ограничивает конец или прерывание цепочки асинхронных вызовов и ввода-вывода, привязанной к домену.
Если к текущему контексту привязано несколько вложенных доменов, exit() выходит из всех вложенных в этот домен.
exit() меняет только активный домен, не сам объект. enter() и exit() можно вызывать произвольное число раз для одного домена.
domain.intercept(callback)¶
callback<Function>функция обратного вызова- Возвращает:
<Function>перехватывающая функция
Почти то же, что domain.bind(callback), но помимо перехвата выброшенных ошибок перехватывает объекты Error, переданные первым аргументом в функцию.
Типичный шаблон if (err) return callback(err); можно заменить одним обработчиком ошибок в одном месте.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
domain.remove(emitter)¶
emitter<EventEmitter>эмиттер, удаляемый из домена
Противоположность domain.add(emitter). Снимает обработку домена с указанного эмиттера.
domain.run(fn[, ...args])¶
fn<Function>...args<any>
Выполняет переданную функцию в контексте домена, неявно связывая все эмиттеры событий, таймеры и низкоуровневые запросы, созданные в этом контексте. Опционально в функцию передаются аргументы.
Это базовый способ использования домена.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
В этом примере сработает обработчик d.on('error'), а не аварийное завершение.
Домены и промисы¶
Начиная с Node.js 8.0.0, обработчики промисов выполняются в том домене, в котором был вызван .then() или .catch():
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
Колбэк можно привязать к конкретному домену через domain.bind(callback):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
Домены не подменяют механизмы обработки ошибок промисов: для необработанных отклонений Promise событие 'error' не генерируется.