NodeJS - setTimeout (fn, 0) проти setImmediate (fn)


Відповіді:


71

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

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

Також (setTimeout, 0) буде повільним, оскільки він перевірить таймер принаймні один раз перед виконанням. Часом це може бути вдвічі повільнішим. Ось еталон.

var Suite = require('benchmark').Suite
var fs = require('fs')

var suite = new Suite

suite.add('deffered.resolve()', function(deferred) {
  deferred.resolve()
}, {defer: true})

suite.add('setImmediate()', function(deferred) {
  setImmediate(function() {
    deferred.resolve()
  })
}, {defer: true})

suite.add('setTimeout(,0)', function(deferred) {
  setTimeout(function() {
    deferred.resolve()
  },0)
}, {defer: true})

suite
.on('cycle', function(event) {
  console.log(String(event.target));
})
.on('complete', function() {
  console.log('Fastest is ' + this.filter('fastest').pluck('name'));
})
.run({async: true})

Вихідні дані

deffered.resolve() x 993 ops/sec ±0.67% (22 runs sampled)
setImmediate() x 914 ops/sec ±2.48% (57 runs sampled)
setTimeout(,0) x 445 ops/sec ±2.79% (82 runs sampled)

Перший дає уявлення про найшвидші дзвінки. Ви можете перевірити себе, чи не викликається setTimeout вдвічі частіше, ніж інші. Також пам’ятайте, що setImmediate налаштується на виклики вашої файлової системи. Отже, під навантаженням він буде працювати менше. Я не думаю, що setTimeout може зробити краще.

setTimeout - це ненав’язливий спосіб виклику функцій через деякий час. Це так само, як у браузері. Можливо, він не підходить для сторони сервера (подумайте, чому я використав benchmark.js не setTimeout).


3
Важливо зазначити, що setTimeout підлягає примусовій затримці щонайменше чотири мілісекунди, якщо вкладений п’ять разів. див. специфікацію html
Джек Аллан

Це джерело (з іншої відповіді), здається, спростовує деякі твердження тут: voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout
Дмитро Зайцев,

17

Чудова стаття про те, як працює цикл подій, і виправляє деякі помилки. http://voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout/

Посилаючись на статтю:

setImmediateзворотні дзвінки викликаються після того, як зворотні виклики вводу-виводу закінчені або закінчився час очікування. setImmediate зворотні виклики розміщуються в Check Queue, які обробляються після I / O Queue.

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


Черга setTimeout обробляється до зворотних викликів вводу-виводу. посилання: nodejs.org/en/docs/guides/event-loop-timers-and-nexttick
людина

6

setImmediate () - це планування негайного виконання зворотного виклику після зворотних викликів подій вводу-виводу та до setTimeout та setInterval.

setTimeout () - запланувати виконання одноразового зворотного виклику після мілісекунд затримки.

Про це говорять документи.

setTimeout(function() {
  console.log('setTimeout')
}, 0)

setImmediate(function() {
  console.log('setImmediate')
})

Якщо запустити наведений вище код, результат буде таким ... навіть незважаючи на те, що в поточному документі зазначено: "Щоб запланувати" негайне "виконання зворотного виклику після зворотних викликів подій вводу-виводу та перед setTimeout і setInterval." ..

Результат ..

setTimeout

setImmediate

Якщо ви обернете приклад іншим таймером, він завжди друкує setImmediate, а потім setTimeout.

setTimeout(function() {
  setTimeout(function() {
    console.log('setTimeout')
  }, 0);
  setImmediate(function() {
    console.log('setImmediate')
  });
}, 10);

То коли ви віддасте перевагу одному перед іншим?
Шломі Шварц

21
Ви не пояснили, чому відбувається те, що ви показали. Ця відповідь мені не була корисною.
Клінт Іствуд,

3
@Savannah У своєму першому результаті, будь ласка, поясніть, чому setTimeout виконується першим перед setImmediate
Агус Сіяхпутра


1
SetImmediate не буде виконуватися перед setTimeout і setInterval весь час
Mithun GS

2

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


1
Я б сказав, що основною причиною використання setTimeout замість setImmediate є те, що ваш код повинен виконуватися браузерами, які не реалізували setImmediate. Навіть тоді ви можете просто створити прокладку.
Григорій Магаршак 01.03.15

9
Це необґрунтована порада. Якщо все просить пройти першим, виникаючі робочі характеристики асинхронного виконання будуть смітними порівняно з чергою в кінці. setTimeoutмає бути переходом, з setImmediateвикористанням лише тоді, коли це показано необхідним.
Rich Remer

1

Повністю незадоволений наданими відповідями. Я розмістив тут, на мою думку, кращі відповіді: https://stackoverflow.com/a/56724489/5992714

Запитання - це можливий дублікат Чому поведінка setTimeout (0) та setImmediate () невизначена при використанні в основному модулі?


1
Будь ласка, не публікуйте абсолютно однакову відповідь на два запитання. Якщо питання різні, адаптуйте відповідь на кожне. Якщо вони однакові, позначте або проголосуйте, щоб закрити його як копію.
Том

@TomZych зазначив.
людина

0

Я думаю, що відповідь Navya S є неправильною, ось мій тестовий код:

let set = new Set();

function orderTest() {
  let seq = [];
  let add = () => set.add(seq.join());
  setTimeout(function () {
    setTimeout(function () {
      seq.push('setTimeout');
      if (seq.length === 2) add();
    }, 0);

    setImmediate(function () {
      seq.push('setImmediate');
      if (seq.length === 2) add();
    });
  }, 10);
}

// loop 100 times
for (let i = 0; i < 100; i++) {
  orderTest();
}

setTimeout(() => {
  // will print one or two items, it's random
  for (item of set) {
    console.log(item);
  }
}, 100);

Пояснення тут


0

setTimeout (fn, 0) можна використовувати для запобігання замерзанню браузера під час масового оновлення. наприклад, у websocket.onmessage, у вас можуть бути зміни в html, і якщо повідомлення продовжуватимуть надходити, браузер може зависнути при використанні setImmidiate


0

Щоб глибоко їх зрозуміти, пройдіть один раз фази циклу подій.

SetImmediate: Він виконується на фазі "перевірка". Перевірка фаза називається після фази I / O.

SetTimeOut: Він виконується у фазі "таймера". Таймер фаза є першою фазою , але викликається після I / O фази, а також Перевірка фази.

Щоб отримати вихідні дані детермінованим способом, це буде залежати від того, на якій фазі знаходиться цикл подій; відповідно, ми можемо використовувати функцію з двох.


-4

використовуйте setImmediate (), щоб не блокувати цикл подій. Зворотний виклик буде виконуватися в наступному циклі події, як тільки завершиться поточний.

використовуйте setTimeout () для контрольованих затримок. Функція буде працювати після зазначеної затримки. Мінімальна затримка - 1 мілісекунда.

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