Як працює setTimeout в Node.JS?


112

Я здогадуюсь, що як тільки він буде виконаний, він знаходиться в черзі, але в черзі є певна впевненість, що він викличе рівно через X мілісекунд? Або інші важкі завдання, які стоять на черзі, затримають його?


14
Жодна операційна система в реальному часі ніколи не дасть можливість гарантувати серйозну точність. Всілякі речі в системі можуть перешкоджати механізму таймера.
Pointy

Відповіді:


174

Семантика setTimeout приблизно така сама, як у веб-браузері: аргумент тайм-ауту - це мінімальна кількість мс, яку потрібно чекати перед виконанням, а не гарантія. Крім того, проходження 0, нечислового чи негативного числа змусить зачекати мінімальну кількість мс. У Node це 1 мс, але в браузерах це може бути аж 50 мс.

Причиною цього є те, що JavaScript не передбачається. Розглянемо цей приклад:

setTimeout(function () {
  console.log('boo')
}, 100)
var end = Date.now() + 5000
while (Date.now() < end) ;
console.log('imma let you finish but blocking the event loop is the best bug of all TIME')

Потік тут:

  1. графік часу очікування на 100 мс.
  2. зайнятий 5000мс.
  3. повернутися до циклу подій. перевірити наявність очікуваних таймерів та виконання.

Якщо цього не було, то у вас може бути один біт JavaScript "перервати" інший. Нам доведеться налаштувати мутекси та семафори тощо, щоб уникнути подібного коду вкрай важко:

var a = 100;
setTimeout(function () {
  a = 0;
}, 0);
var b = a; // 100 or 0?

Однопоточність виконання JavaScript у Node робить роботу набагато простішою, ніж більшість інших стилів одночасності. Звичайно, компроміс полягає в тому, що можлива погана поведінка частини програми блокувати всю справу нескінченним циклом.

Це кращий демон для битви, ніж складність випередження? Це залежить.


20
Ви отримуєте +1 за виключно точне console.logповідомлення.
Фонд позову Моніки

Мені подобається, як ти перекладав TIME у свій рядок. Дуже гарне пояснення !!!
Аліссон

43

Ідея неблокування полягає в тому, що ітерації циклу швидкі. Отже, для повторення кожної галочки повинно пройти досить короткий час, щоб setTimeout був точним до розумної точності (вимкнено, можливо, <100 мс або близько того).

Теоретично, хоча ти маєш рацію. Якщо я напишу заявку і заблокую галочку, тоді setTimeouts буде відкладено. Отже, щоб відповісти на ваше запитання, хто може запевнити, що час setTimeouts виконується вчасно? Ви, написавши неблокуючий код, можете контролювати ступінь точності майже до будь-якої розумної міри точності.

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

Спробуйте цей код або у вашому браузері, або у вузлі, і ви побачите, що немає гарантії точності, навпаки, setTimeout буде дуже пізно:

var start = Date.now();

// expecting something close to 500
setTimeout(function(){ console.log(Date.now() - start); }, 500);

// fiddle with the number of iterations depending on how quick your machine is
for(var i=0; i<5000000; ++i){}

Якщо інтерпретатор не оптимізує цикл подалі (який не має хрому), ви отримаєте щось у тисячах. Зніміть петлю, і ви побачите, що це 500 на носі ...


9

Єдиний спосіб забезпечити виконання коду - це розмістити свою логіку setTimeout в іншому процесі.

Використовуйте модуль дочірнього процесу для нерестування нової програми node.js, яка виконує вашу логіку і передає дані цьому процесу через якийсь потік (можливо, tcp).

Таким чином, навіть якщо якийсь довгий код блокування запущений у вашому головному процесі, ваш дочірній процес вже розпочався сам і помістив setTimeout у новий процес та нову нитку і таким чином запуститься, коли ви цього очікуєте.

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

Як правило, використання дочірніх процесів та запуску декількох додатків у вузлах як окремих процесів разом із балансиром завантаження або спільним сховищем даних (наприклад, redis) є важливим для масштабування вашого коду.


9

setTimeoutє своєрідною ниткою , вона проводить операцію протягом певного часу та виконує.

setTimeout(function,time_in_mills);

тут перший аргумент повинен бути типом функції; як приклад, якщо ви хочете надрукувати своє ім'я через 3 секунди, ваш код повинен бути таким, як нижче.

setTimeout(function(){console.log('your name')},3000);

Ключовим моментом, що потрібно пам’ятати, є те, що ви хочете зробити, використовуючи setTimeoutметод, зробити це всередині функції . Якщо ви хочете викликати якийсь інший метод, аналізуючи деякі параметри, ваш код повинен виглядати так:

setTimeout(function(){yourOtherMethod(parameter);},3000);

8

setTimeout(callback,t)використовується для запуску зворотного виклику після принаймні t мілісекунди . Фактична затримка залежить від багатьох зовнішніх факторів, таких як зернистість таймера ОС та завантаження системи.

Отже, є ймовірність, що він буде викликаний трохи після встановленого часу, але ніколи не буде викликаний раніше.

Таймер не може тривати більше 24,8 днів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.