#nodejs_api
У Node.js v16 змінилися принципи роботи з таймерами: додано
timers/promises аналогічно fs/promises. Розглянемо best practices по роботі з ними:1️⃣ Як підключати? Ось приклад поганого коду:
import { setTimeout } from 'timers/promises';Тут ми робимо variables shadowing, так як перевизначаємо в поточному файлі однойменну глобальну змінну setTimeout. А ще імена built-in модулів краще писати з префіксом
node:. Тобто гарний код:import { setTimeout as wait } from 'node:timers/promises';2️⃣ Коли який таймер використовувати?
👉 Найчастіше використовується промісіфікований
setTimeout. За допомогою нього реалізується затримка виконання.👉 За допомогою промісіфікованого
setInterval створюється AsyncIterable. Приклад:for await (const startTime of setInterval(100, Date.now())) { if ((Date.now() - startTime) > 1000) break; // some logic}👉 setImmediate використовується щоб розблокувати EventLoop. Приклад
3️⃣ Порівняння з callback таймерами
👉 callback-based доступні глобально, а промісіфіковані потрібно імпортувати.
👉 У обох випадках використовується ref, щоб визначити чи буде таймер тримати event loop активним
👉 Скасування в callback-based відбувається через clearTimeout (і його аналоги), а у промісіфікованого через AbortController.
👉 В callback-based таймерах ми можемо передати аргументи для хендлера, а промісіфікований можна сказати, яке значення буде повертати проміс.
4️⃣ Ще раз про колізії імен
Мені не подобається, що імена в callback і промісах версій співпадають. Це не створює проблем у модулі fs, так як його методи не доступні глобально, але в таймерах це ускладнює підтримку коду. Як альтернативу я рекомендую використовувати об'єкт scheduler. Виглядає це так
import { scheduler } from 'node:timers/promises';await scheduler.wait(100);Його додали у лютому 2022 року з флагом experimental. Аналіз коду показує, що всі його методи це синтаксичний сахар:
👉 scheduler.yield() це теж саме що setImmediate() без аргументів.
👉 scheduler.wait(delay, options) це теж саме що setTimeout(delay, undefined, options) за винятком того, що опція ref не підтримується.