Домен¶
Стабильность: 0 – устарело или набрало много негативных отзывов
Эта фича является проблемной и ее планируют изменить. Не стоит полагаться на нее. Использование фичи может вызвать ошибки. Не стоит ожидать от нее обратной совместимости.
Этот модуль находится в процессе депривации. Как только будет завершена разработка API замены, этот модуль будет полностью деприватизирован. У большинства разработчиков не должно быть причин использовать этот модуль. Пользователи, которым абсолютно необходима функциональность, предоставляемая доменами, могут использовать его в настоящее время, но должны ожидать, что в будущем им придется перейти на другое решение.
Домены предоставляют возможность обрабатывать несколько различных операций ввода-вывода как единую группу. Если любой из эмиттеров событий или обратных вызовов, зарегистрированных в домене, выдает событие 'error'
или выбрасывает ошибку, то объект домена будет уведомлен, а не потеряет контекст ошибки в обработчике process.on('uncaughtException')
или заставит программу немедленно завершиться с кодом ошибки.
Предупреждение: Не игнорируйте ошибки!¶
Обработчики ошибок домена не заменяют закрытие процесса при возникновении ошибки.
По самой природе того, как throw
работает в JavaScript, почти никогда нет никакого способа безопасно "подхватить то, на чем остановились", без утечки ссылок или создания какого-то другого неопределенного хрупкого состояния.
Самый безопасный способ отреагировать на брошенную ошибку - это завершить процесс. Конечно, в обычном веб-сервере может быть много открытых соединений, и нецелесообразно внезапно закрывать их из-за того, что ошибка была спровоцирована кем-то другим.
Лучший подход - послать ответ об ошибке на запрос, который вызвал ошибку, а остальным позволить завершить работу в обычное время и прекратить прослушивание новых запросов в этом рабочем.
Таким образом, использование domain
идет рука об руку с модулем кластера, поскольку основной процесс может форкнуть новый рабочий, когда рабочий столкнулся с ошибкой. Для программ Node.js, которые масштабируются на несколько машин, завершающий прокси-сервер или реестр сервисов может принять к сведению сбой и отреагировать соответствующим образом.
Например, это не очень хорошая идея:
ПРЕДУПРЕЖДЕНИЕ! ПЛОХАЯ ИДЕЯ! | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Используя контекст домена, и устойчивость разделения нашей программы на несколько рабочих процессов, мы можем реагировать более адекватно, и обрабатывать ошибки с гораздо большей безопасностью.
Намного лучше! | |
---|---|
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 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
|
Дополнения к объектам Error
¶
Каждый раз, когда объект Error
направляется через домен, к нему добавляется несколько дополнительных полей.
error.domain
Домен, который первым обработал ошибку.error.domainEmitter
Эмиттер события, который испустил событие'error'
с объектом ошибки.error.domainBound
Функция обратного вызова, которая была привязана к домену и передала ошибку в качестве первого аргумента.error.domainThrown
Булево значение, указывающее, была ли ошибка брошена, испущена или передана связанной функции обратного вызова.
Неявное связывание¶
Если домены используются, то все новые объекты EventEmitter
(включая объекты Stream, запросы, ответы и т.д.) будут неявно привязаны к активному домену в момент их создания.
Кроме того, обратные вызовы, передаваемые низкоуровневым запросам цикла событий (например, fs.open()
или другим методам, принимающим обратные вызовы), будут автоматически привязаны к активному домену. Если они отбрасываются, то домен перехватывает ошибку.
Во избежание чрезмерного использования памяти, сами объекты Domain
не добавляются неявно в качестве дочерних объектов активного домена. Если бы это было так, то было бы слишком легко предотвратить правильную сборку мусора для объектов запроса и ответа.
Чтобы вложить объекты Domain
в качестве дочерних объектов родительского Domain
, они должны быть явно добавлены.
Неявное связывание направляет брошенные ошибки и события 'error'
в событие 'error'
домена, но не регистрирует EventEmitter
на Domain
. Неявное связывание заботится только о выброшенных ошибках и событиях '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 29 |
|
domain.create()
.¶
- Возвращает: {Домен}
Класс: Домен
¶
- Расширяет:
<EventEmitter>
Класс Domain
инкапсулирует функциональность маршрутизации ошибок и не пойманных исключений в активный объект Domain
.
Для обработки ошибок, которые он ловит, слушайте его событие 'error'
.
domain.members
¶
Массив таймеров и эмиттеров событий, которые были явно добавлены в домен.
domain.add(emitter)
¶
emitter
{EventEmitter|Timer} эмиттер или таймер для добавления в домен
Явно добавляет эмиттер в домен. Если обработчики событий, вызванные эмиттером, выдадут ошибку, или если эмиттер выдаст событие 'error'
, оно будет перенаправлено в событие 'error'
домена, как и при неявном связывании.
Это также работает с таймерами, которые возвращаются из setInterval()
и setTimeout()
. Если их функция обратного вызова бросает, она будет поймана обработчиком '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 17 |
|
domain.enter()
.¶
Метод enter()
используется методами run()
, bind()
и intercept()
для установки активного домена. Он устанавливает domain.active
и process.domain
в домен и неявно помещает домен в стек доменов, управляемый модулем 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 20 21 22 23 24 |
|
domain.remove(emitter)
¶
emitter
{EventEmitter|Timer} эмиттер или таймер, который должен быть удален из домена.
Противоположность domain.add(emitter)
. Удаляет обработку домена с указанного эмиттера.
domain.run(fn[, ...args])
¶
fn
<Function>
...args
{любая}
Запускает указанную функцию в контексте домена, неявно связывая все эмиттеры событий, таймеры и низкоуровневые запросы, созданные в этом контексте. По желанию функции могут быть переданы аргументы.
Это самый простой способ использования домена.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
В этом примере сработает обработчик d.on('error')
, а не аварийно завершит программу.
Домены и обещания¶
Начиная с Node.js 8.0.0, обработчики обещаний запускаются внутри домена, в котором был сделан вызов .then()
или .catch()
:
``js const d1 = domain.create(); const d2 = domain.create();
let p; d1.run(() => { p = Promise.resolve(42); });
d2.run(() => { p.then((v) => { // выполняется в d2 }); });
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
Домены не будут вмешиваться в механизмы обработки ошибок для обещаний. Другими словами, для необработанных отказов Promise
не будет выдаваться событие 'error'
.