|
| 1 | +--- |
| 2 | +title: Таймеры в Node.js |
| 3 | +layout: docs.hbs |
| 4 | +--- |
| 5 | + |
| 6 | +# Таймеры в Node.js и за пределами |
| 7 | + |
| 8 | +Модуль таймеров в Node.js содержит функции, которые выполняют код по истечении |
| 9 | +заданного периода времени. Таймеры не нужно импортировать через `require()`, так как |
| 10 | +все методы доступны глобально для эмуляции браузерного JavaScript API. |
| 11 | +Для того, чтобы полностью понять когда будут выполняться функции таймера, имеет смысл |
| 12 | +прочитать об [Event Loop](/en/docs/guides/event-loop-timers-and-nexttick/) в Node.js. |
| 13 | + |
| 14 | +## Управление временным континуумом с Node.js |
| 15 | + |
| 16 | +API Node.js предоставляет несколько способов планирования кода, который нужно |
| 17 | +выполнить, в какой-то момент в будущем. Приведенные ниже функции могут показатья знакомыми, так как |
| 18 | +они доступны в большинстве браузеров, но Node.js на самом деле предоставляет |
| 19 | +свою реализацию этих методов. Таймеры очень тесно интегрируются с системой, и, несмотря на то, |
| 20 | +что API Node.js отражает API браузера, все равно имеются некоторые различия в реализации. |
| 21 | + |
| 22 | +### "Когда я скажу" Выполнение ~ *`setTimeout()`* |
| 23 | + |
| 24 | +`setTimeout()` может использоваться для планирования выполнения кода после назначенного |
| 25 | +количества миллисекунд. Эта функция аналогична [`window.setTimeout()`](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout) из JavaScript API браузера, однако строка кода не может передаваться |
| 26 | +в качестве аргумента для выполнения. |
| 27 | + |
| 28 | +`setTimeout()` первым параметром принимает функцию, которую нужно выполнить, и задержку в миллисекундах, |
| 29 | +как число, в качестве второго параметра. Также можно перечислить дополнительные аргументы и они |
| 30 | +будут переданы функции. Вот пример этого: |
| 31 | + |
| 32 | +```js |
| 33 | +function myFunc(arg) { |
| 34 | + console.log(`arg was => ${arg}`); |
| 35 | +} |
| 36 | + |
| 37 | +setTimeout(myFunc, 1500, 'funky'); |
| 38 | +``` |
| 39 | + |
| 40 | +Функция `myFunc()` выполнится через время, максимально приближенное к |
| 41 | +1500 миллисекундам (или 1.5 секунды), из-за вызова `setTimeout()`. |
| 42 | + |
| 43 | +Нельзя полагаться на то, что тайм-аут выполнится после этого *точного* количества миллисекунд. |
| 44 | +Это связано с тем, что другой исполняемый код, который блокирует или удерживает цикл событий, |
| 45 | +отодвигает выполнение тайм-аута на задний план. *Единственной* гарантией является то, что |
| 46 | +тайм-аут не будет выполнен раньше, чем заданный интервал. |
| 47 | + |
| 48 | +`setTimeout()` возвращает объект `Timeout`, который можно использовать в качестве ссылки |
| 49 | +на тайм-аут, который был установлен. Этот объект можно использовать для отмены тайм-аута (см. `clearTimeout()` ниже), а также для изменения поведения при выполнении (см. `unref()` ниже). |
| 50 | + |
| 51 | +### "Сразу после этого" Выполнение ~ *`setImmediate()`* |
| 52 | + |
| 53 | +`setImmediate()` выполнит код в конце текущего цикла событий. |
| 54 | +Этот код будет выполняться *после* любых операций ввода-вывода в текущем цикле событий и |
| 55 | +*перед* любым запланированными таймерами для следующего цикла событий. Такое выполнение кода |
| 56 | +можно рассматривать как "сразу после этого", то есть любой код, следующий за вызовом |
| 57 | +функции `setImmediate()`, будет выполняться до аргумента функции `setImmediate()`. |
| 58 | + |
| 59 | +Первым аргументом `setImmediate()` будет функция, которую нужно выполнить. Все последующие |
| 60 | +аргументы будут переданы функции при ее выполнении. Вот пример: |
| 61 | + |
| 62 | +```js |
| 63 | +console.log('before immediate'); |
| 64 | + |
| 65 | +setImmediate((arg) => { |
| 66 | + console.log(`executing immediate: ${arg}`); |
| 67 | +}, 'so immediate'); |
| 68 | + |
| 69 | +console.log('after immediate'); |
| 70 | +``` |
| 71 | + |
| 72 | +Функция, переданная в `setImmediate()`, будет выполнена после того, |
| 73 | +как будет выполнен весь исполняемый код, и в консоли мы увидим следующее: |
| 74 | + |
| 75 | +``` |
| 76 | +before immediate |
| 77 | +after immediate |
| 78 | +executing immediate: so immediate |
| 79 | +``` |
| 80 | + |
| 81 | +`setImmediate()` возвращает объект `Immediate`, который можно использовать для отмены |
| 82 | +запланированного immediate (см. `clearImmediate()` ниже). |
| 83 | + |
| 84 | +Примечание: Не путайте `setImmediate()` и `process.nextTick()`. Между ними есть |
| 85 | +несколько основных различий. Во-первых, `process.nextTick()` выполнится *перед* любыми `Immediate`, |
| 86 | +а также перед любыми запланированными операциями ввода/вывода. Во-вторых, `process.nextTick()` не подлежит |
| 87 | +отмене, имеется в виду, что после того как вы запланировали выполнение кода с помощью `process.nextTick()`, |
| 88 | +то его выполнение не может быть приостановлено, также как и с обычной функцией. Обратитесь к |
| 89 | +[этому руководству](/en/docs/guides/event-loop-timers-and-nexttick/#process-nexttick), чтобы лучше понять |
| 90 | +работу `process.nextTick()`. |
| 91 | + |
| 92 | +### "Бесконечный цикл" Выполнение ~ *`setInterval()`* |
| 93 | + |
| 94 | +Если у вас есть код, который нужно выполнить несколько раз, то можно использовать |
| 95 | +для этого `setInterval()`. `setInterval()` принимает параметром функцию, которая будет |
| 96 | +выполняться бесконечное количество раз с заданным интервалом в миллисекундах, сам интервал передается |
| 97 | +вторым параметром. Как и в случае с `setTimeout()` можно передавать дополнительные аргументы, |
| 98 | +эти аргументы будут переданы функции при вызове. Также как и с `setTimeout()`, задержка не может |
| 99 | +быть гарантирована из-за операций, которые могут удерживать цикл событий, следовательно, нужно |
| 100 | +рассматривать эту задержку как приблизительную. Смотрите пример ниже: |
| 101 | + |
| 102 | +```js |
| 103 | +function intervalFunc() { |
| 104 | + console.log('Cant stop me now!'); |
| 105 | +} |
| 106 | + |
| 107 | +setInterval(intervalFunc, 1500); |
| 108 | +``` |
| 109 | + |
| 110 | +В примере выше `intervalFunc()` будет выполняться каждые 1500 миллисекунд |
| 111 | +или 1.5 секунд, до тех пор, пока ее не остановят (см. ниже). |
| 112 | + |
| 113 | +`setInterval()`, также как и `setTimeout()` возвращает объект `Timeout`, который |
| 114 | +можно использовать в качестве ссылки для изменения установленного интервала. |
| 115 | + |
| 116 | +## Отмена грядущего |
| 117 | + |
| 118 | +Что нужно сделать, чтобы отменить `Timeout` или `Immediate`? `setTimeout()`, `setImmediate()` и |
| 119 | +`setInterval()` возвращают объект таймера, который можно использовать в качестве ссылки на установленные |
| 120 | +`Timeout` и `Immediate` объекты. При передаче этого объекта в соответствующую функцию `clear` - выполнение |
| 121 | +этого объекта будет полностью остановлено. `clearTimeout()`, `clearImmediate()` и `clearInterval()` - это те |
| 122 | +самые специальные функции. Давайте посмотрим на пример ниже: |
| 123 | + |
| 124 | +```js |
| 125 | +const timeoutObj = setTimeout(() => { |
| 126 | + console.log('timeout beyond time'); |
| 127 | +}, 1500); |
| 128 | + |
| 129 | +const immediateObj = setImmediate(() => { |
| 130 | + console.log('immediately executing immediate'); |
| 131 | +}); |
| 132 | + |
| 133 | +const intervalObj = setInterval(() => { |
| 134 | + console.log('interviewing the interval'); |
| 135 | +}, 500); |
| 136 | + |
| 137 | +clearTimeout(timeoutObj); |
| 138 | +clearImmediate(immediateObj); |
| 139 | +clearInterval(intervalObj); |
| 140 | +``` |
| 141 | + |
| 142 | +## Оставляя тайм-ауты позади |
| 143 | + |
| 144 | +Помните, что `setTimeout` и `setInterval` возвращают объект `Timeout`. |
| 145 | +У объекта `Timeout` есть два метода, чтобы расширить свое поведение, это |
| 146 | +`unref()` и `ref()`. Если есть объект `Timeout`, запланированный с использованием функции `set`, |
| 147 | +то для этого объекта может быть вызвана `unref()`. Это немного изменит поведение тем, что объект |
| 148 | +`Timeout` не выполнит запланированный код, *если это последний код, который нужно выполнить*. Объект `Timeout` |
| 149 | +не будет удерживать процесс в ожидании выполнения. |
| 150 | + |
| 151 | +Аналогичным образом, объект `Timeout`, на котором был вызван `unref()`, |
| 152 | +может убрать это поведение, вызвав `ref()` на том же `Timeout` объекте, что затем |
| 153 | +обеспечит его выполнение. Однако имейте в виду, что это не *точно* восстанавливает |
| 154 | +исходное поведение по причинам производительности. Давайте взглянем на примеры ниже: |
| 155 | + |
| 156 | +```js |
| 157 | +const timerObj = setTimeout(() => { |
| 158 | + console.log('will i run?'); |
| 159 | +}); |
| 160 | + |
| 161 | +// если оставить без внимания, то это выражение |
| 162 | +// не позволит выполниться тайм-ауту выше, так как сам тайм-аут |
| 163 | +// будет единственным, что не позволит программе завершиться |
| 164 | +timerObj.unref(); |
| 165 | + |
| 166 | +// мы можем вернуть его к жизни вызвав ref() внутри immediate |
| 167 | +setImmediate(() => { |
| 168 | + timerObj.ref(); |
| 169 | +}); |
| 170 | +``` |
| 171 | + |
| 172 | +## Далее по событийному циклу |
| 173 | + |
| 174 | +В событийном цикле и таймерах можно найти гораздо больше информации, чем в |
| 175 | +этом руководстве. Чтобы узнать больше о внутренностях цикла событий Node.js и о том, |
| 176 | +как работают таймеры во время выполнения - взгляните на это руководство: [The Node.js Event Loop, Timers, and process.nextTick()](/en/docs/guides/event-loop-timers-and-nexttick/). |
0 commit comments