Як правильно використовувати події в Node.js

До того, як програмоване на основі подій набуло популярності, стандартний спосіб спілкування між різними частинами програми був досить простим: компонент, який хотів надіслати повідомлення іншому, явно викликав метод цього компонента. Але керований подіями код написаний для реагування, а не для виклику .

Переваги Eventing

Цей підхід призводить до того, що наші компоненти набагато більш розв’язані . Продовжуючи писати заявку, ми визначаємо події в дорозі. Ми звільняємо їх у потрібний час і прикріплюємо до кожного одного або більше слухачів подій . Розширення функціональних можливостей стає набагато простішим. Ми можемо додати більше слухачів до певної події. Ми не втручаємось у існуючі слухачі або частину програми, з якої було запущено подію. Ми говоримо про шаблон спостерігача.

Проектування архітектури, керованої подіями

Визначення подій є досить важливим. Нам не хочеться видаляти / замінювати існуючі події з системи. Це може змусити нас видалити / змінити будь-яку кількість слухачів, які були приєднані до події. Загальний принцип, який я використовую, полягає в тому, щоб розглянути можливість запуску події лише тоді, коли одиниця бізнес-логіки завершує виконання.

Тож скажіть, що ви хочете розіслати купу різних листів після реєстрації користувача. Тепер сам процес реєстрації може включати багато складних кроків та запитів. Але з точки зору бізнесу це один крок. І кожен електронний лист, який потрібно розіслати, також є окремими кроками. Тому було б сенсом запускати подію, як тільки реєстрація закінчується. У нас є кілька слухачів, кожен відповідальний за розсилку одного типу електронного листа.

Асинхронна, керована подіями архітектура вузла має певні типи об'єктів, які називаються "випромінювачами". Вони видають іменовані події, які викликають виклик функцій, які називаються «слухачами». Усі об'єкти, що випускають події, є екземплярами класу EventEmitter. Використовуючи його, ми можемо створювати власні події:

Приклад

Давайте скористаємося вбудованим модулем подій (до якого я радимо детально ознайомитися), щоб отримати доступ EventEmitter.

Це частина програми, де наш сервер отримує HTTP-запит, зберігає нового користувача та випускає подію:

І окремий модуль, куди ми підключаємо слухача:

Доброю практикою є відокремлення політики від реалізації. У цьому випадку політика означає, які слухачі підписані на які події. Реалізація означає самих слухачів.

Це розділення дозволяє слухачеві також стати повторно використаним. Він може бути приєднаний до інших подій, які надсилають одне і те ж повідомлення (об'єкт користувача). Важливо також згадати, що коли до однієї події приєднано кілька слухачів, вони будуть виконуватися синхронно та в тому порядку, в якому вони були приєднані . Отже, someOtherListenerбуде працювати після sendEmailOnRegistrationзакінчення виконання.

Однак, якщо ви хочете, щоб ваші слухачі працювали асинхронно, ви можете просто обернути їх реалізації setImmediateтаким чином:

Зберігайте своїх слухачів у чистоті

Дотримуйтесь принципу єдиної відповідальності, коли пишете слухачам. Один слухач повинен робити лише одне і робити це добре. Уникайте, наприклад, писати занадто багато умовних умов у слухачі, які вирішують, що робити залежно від даних (повідомлення), переданих подією. У цьому випадку було б набагато доцільніше використовувати різні події:

Від'єднання слухачів явно, коли це необхідно

У попередньому прикладі наші слухачі мали абсолютно незалежні функції. Але у випадках, коли слухач асоціюється з об’єктом (це метод), його потрібно вручну від’єднати від подій, на які він передплатився. В іншому випадку об’єкт ніколи не збиратиметься сміттям, оскільки на частину об’єкта (слухач) надалі буде посилатися зовнішній об’єкт (випромінювач). Таким чином, можливість витоку пам'яті.

Наприклад, якщо ми створюємо додаток для чату, і ми хочемо, щоб відповідальність за показ сповіщення про надходження нового повідомлення в кімнату чату, до якого користувач підключився, лежала в самому об’єкті користувача, ми можемо зробити це:

Коли користувач закриває свою вкладку або на деякий час втрачає з’єднання з Інтернетом, природно, ми можемо захотіти запустити зворотний виклик на стороні сервера, який повідомляє інших користувачів про те, що хтось із них щойно вийшов з мережі. На даний момент, звичайно, немає сенсу displayNewMessageNotificationвикликати автономного користувача. Її буде продовжувати викликати в нових повідомленнях, якщо ми її явно не видалимо. Якщо ми цього не зробимо, крім непотрібного виклику, об'єкт користувача також буде залишатися в пам'яті на невизначений час. Тому не забудьте зателефонувати disconnectFromChatroomна зворотний виклик на стороні сервера, який виконується, коли користувач переходить у автономний режим.

Обережно

Ослаблене зв’язування в архітектурах, керованих подіями, також може призвести до збільшення складності, якщо ми не будемо обережні. Буде важко відстежувати залежності в нашій системі. Наш додаток стане особливо схильним до цієї проблеми, якщо ми почнемо випускати події зсередини слухачів. Це може спричинити ланцюг несподіваних подій.