23. Уроки Node.js. Домены, “асинхронный try..catch”. Часть 2.

node23_2

Продолжаем наш урок. Давайте немного усложним этот пример, добавив работу с файлами вот таким образом:

Запускаем. Как ни странно, оно все еще работает. Почему? Как домен из данной функции перекочевал в fs.readFile(__filename, function()? Да все оттуда же. Потому что внутренняя реализация функции readFile знает про домены. Когда она запускает callback, то она запускает его в контексте того же домена. Благодаря этому все хорошо.

Рассмотрим последний пример.  Создаем новый объект:

всю эту логику, которая генерирует ошибку, поместим внутрь обработчика события:

И для того, чтобы еще больше все запутать, вынесем этот код вниз. То есть, мы создаем объект в одном месте, а ошибка будет вообще после того, как запуск в домене закончился. Обработает ли ее домен? Запускаем наш код, полностью он выглядит вот так:

Как видим, все отлично обработалось. Каким образом эта функция узнала про домен? Все благодаря интеграции. Ведь сервер – это EventEmitter. Этот модуль знает про домены, и, когда создается любой EventEmitter, если есть текущий активный домен, то он получает ссылку на него, где ее можно вывести. добавим console.log:

Запускаем. Все, есть. После того, как EventEmitter привязан к домену, любые обработчики он запускает именно в контексте этого домена. Конечно же, если сервер создается вне активного домена, то ни о каком server.domain не может идти и речи. Впрочем, с такими объектами тоже можно иметь дело, необходимо лишь добавить их домен вручную: специальный вызов add:

Если мы сейчас это вызовем, то все будет хорошо, ошибка перехвачена. Единственная тонкость, которую здесь надо иметь в  виду, это управление памятью. Дело в том, что если EventEmitter создан именно в контексте домена, то он получает ссылку, в данном случае server.domain. А если он был создан ранее и добавлен через add, то он получает не только сам ссылку на этот домен, но еще и домен ссылается на него. То есть, у домена есть специальный массив members, где он ссылается на все, что ссылается через  add. Во всяком случае, такова текущая реализация. Соответственно, получается, что с add мы имеем двустороннюю ссылку serverdomain. В результате получается, что память может быть очищена не от сервера в отдельности, не от домена в отдельности, а от них обоих вместе. То есть, если есть какой-то долго живущий домен, и к нему через add  прибавляется много всего, то память не будет очищена, пока домен не умрет, либо пока когда это станет возможным, не будет вызов d.remove(server). Как правило, в скриптах эти штуки используют редко, обычно стараются создавать все, что нужно, внутри домена, и таких проблем не возникает.

Вернемся к примеру, который рассматривали в первой части статьи, то есть, к серверу. Перейдите на commit под названием domain_1-11:

Как вы считаете, в чем же дело? Почему ошибка в обработчике запроса вылетела и не была обработана доменом? Как это поправить? Дело в том, что сервер создан вне домена. Таким образом, handler это обработчик события request. Так как сервер создан вне домена, то при вызове обработчика никакой домен ему не передается, и throw, как и раньше, валит весь процесс. Чтобы все было хорошо, достаточно взять этот объект server и создать его внутри вызова run:

Вот так будет все нормально, поскольку сервер привязан к домену. Проверим. Запускаем код. Вызываем Chrome и переходим по тому же url:

http://127.0.0.1:3000/

Теперь домен перехватил ошибку, ничего не упало. С другой стороны, конечно же, задача не может считаться полноценно решенной, потому что нужно что-то ответить посетителю: “извините, ошибка, приходите к нам потом”.

А как нам ответить? Здесьserver.domain перехватил ошибку, но никакой информации о том, где она, у него нет. Для того, чтобы ее получить, мы будем создавать домен отдельно для каждого запроса. Выглядит это следующим образом. Есть два файла. Первый  app.js – главный, основной файл приложения:

Он занимается тем, что запускает сервер, создает домены. Второй – handler.js, модуль, который занимается обработкой запросов:

Итак, из чего состоит app.js?

Мы поговорим об этом в следующей статье. До скорых встреч. Код нашего урока можно найти здесь.

to-be-continued-series-8

Материалы для статьи взяты из следующего скринкаста.

We are looking forward to meeting you on our website soshace.com

About the author

Stay Informed

It's important to keep up
with industry - subscribe!

Stay Informed

Looks good!
Please enter the correct name.
Please enter the correct email.
Looks good!

Related articles

Уроки Express.js . Логгер, Конфигурация, Шаблонизация с EJS. Часть 2.

Favicon – это все connect Middleware, он смотрит, если url имеет вид favicon.ico, то он читает favicon и ...

3. Уроки Express.js. Шаблонизация с EJS: Layout, Block, Partials

В реальной жизни у нас обычно больше, чем один шаблон. Более того, если уж так ...

24.11.2016

Уроки Express.js. Основы и Middleware. Часть 2.

Всем привет! Давайте продолжим наш урок об основах Express и Middleware. Итог (добавим в ...

No comments yet

Sign in

Forgot password?

Or use a social network account

 

By Signing In \ Signing Up, you agree to our privacy policy

Password recovery

You can also try to

Or use a social network account

 

By Signing In \ Signing Up, you agree to our privacy policy