NodeJS - setTimeout (fn, 0) vs setImmediate (fn)

Réponses:

71

setTimeout revient simplement à appeler la fonction après la fin du délai. Chaque fois qu'une fonction est appelée, elle n'est pas exécutée immédiatement, mais mise en file d'attente afin qu'elle soit exécutée après que tous les gestionnaires d'événements en cours d'exécution et actuellement en file d'attente se terminent en premier. setTimeout (, 0) signifie essentiellement s'exécuter après l'exécution de toutes les fonctions actuelles de la file d'attente actuelle. Aucune garantie ne peut être donnée sur le temps que cela pourrait prendre.

setImmediate est similaire à cet égard, sauf qu'il n'utilise pas de file d'attente de fonctions. Il vérifie la file d'attente des gestionnaires d'événements d'E / S. Si tous les événements d'E / S de l'instantané actuel sont traités, il exécute le rappel. Il les met en file d'attente immédiatement après le dernier gestionnaire d'E / S, un peu comme process.nextTick. C'est donc plus rapide.

De plus, (setTimeout, 0) sera lent car il vérifiera la minuterie au moins une fois avant de s'exécuter. Parfois, cela peut être deux fois plus lent. Voici une référence.

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})

Production

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)

Le premier donne une idée des appels les plus rapides possibles. Vous pouvez vérifier vous-même si setTimeout est appelé deux fois moins que l'autre. Rappelez-vous également que setImmediate s'adaptera à vos appels au système de fichiers. Donc, sous charge, il sera moins performant. Je ne pense pas que setTimeout puisse faire mieux.

setTimeout est un moyen non intrusif d'appeler des fonctions après un certain temps. C'est comme si c'était dans le navigateur. Cela peut ne pas convenir pour le côté serveur (pensez pourquoi j'ai utilisé benchmark.js et non setTimeout).

user568109
la source
3
Il est important de noter que setTimeout est soumis à un délai forcé d'au moins quatre millisecondes s'il est imbriqué cinq fois. voir les spécifications html
Jack Allan
Cette source (de l'autre réponse) semble réfuter certaines des déclarations ici: voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout
Dmitri Zaitsev
17

Un excellent article sur le fonctionnement de la boucle d'événements et efface certaines idées fausses. http://voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout/

Citant l'article:

setImmediateles rappels sont appelés une fois que les rappels de file d'attente d'E / S sont terminés ou expirés. Les rappels setImmediate sont placés dans la file d'attente de contrôle, qui sont traités après la file d'attente d'E / S.

setTimeout(fn, 0)les rappels sont placés dans la file d'attente du minuteur et seront appelés après les rappels d'E / S ainsi que les rappels de vérification de la file d'attente. En tant que boucle d'événements, traitez la file d'attente du minuteur en premier à chaque itération, de sorte que celle qui sera exécutée en premier dépend de la boucle d'événements de phase.

Aman Gupta
la source
La file d'attente setTimeout est traitée avant les rappels d'E / S. ref: nodejs.org/en/docs/guides/event-loop-timers-and-nexttick
human
6

setImmediate () est de planifier l'exécution immédiate du rappel après les rappels d'événements d'E / S et avant setTimeout et setInterval.

setTimeout () est de planifier l'exécution d'un rappel unique après un délai de quelques millisecondes.

C'est ce que disent les documents.

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

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

Si vous exécutez le code ci-dessus, le résultat sera comme ceci ... même si la documentation actuelle indique que "Pour planifier l'exécution" immédiate "du rappel après les rappels d'événements d'E / S et avant setTimeout et setInterval." ..

Résultat..

setTimeout

setImmediate

Si vous encapsulez votre exemple dans un autre minuteur, il imprime toujours setImmediate suivi de setTimeout.

setTimeout(function() {
  setTimeout(function() {
    console.log('setTimeout')
  }, 0);
  setImmediate(function() {
    console.log('setImmediate')
  });
}, 10);
Navya S
la source
Alors, quand préférerez-vous l'un à l'autre?
Shlomi Schwartz
21
Vous n'avez pas expliqué pourquoi ce que vous avez montré se produit. Cette réponse ne m'a pas été utile.
Clint Eastwood
3
@Savannah Dans votre premier résultat, veuillez expliquer pourquoi setTimeout a été exécuté avant setImmediate
Agus Syahputra
2
@AgusSyahputra Vérifiez ceci: github.com/nodejs/node-v0.x-archive/issues/25788
Rodrigo Branas
1
SetImmediate ne s'exécutera pas avant setTimeout et setInterval tous les temps
Mithun GS
2

utilisez toujours setImmediate, sauf si vous êtes vraiment sûr que vous en avez besoin setTimeout(,0)(mais je ne peux même pas imaginer, pourquoi). setImmediatecallback sera presque toujours exécuté avant setTimeout(,0), sauf lorsqu'il est appelé au premier tick et au setImmediatecallback.

vkurchatkin
la source
1
Je dirais que la principale raison d'utiliser setTimeout au lieu de setImmediate est que votre code doit être exécuté par des navigateurs qui n'ont pas implémenté setImmediate. Même dans ce cas, vous pouvez simplement créer une cale.
Gregory Magarshak
9
Ce n'est pas un bon conseil. Si tout demande à commencer, les caractéristiques de performance émergentes de l'exécution asynchrone vont être indésirables par rapport à la mise en file d'attente à la fin. setTimeoutdevrait être la référence, à setImmediateutiliser uniquement lorsque cela s'avère nécessaire.
Rich Remer
1

Totalement insatisfait des réponses fournies. J'ai posté ce que je pense être une meilleure réponse ici: https://stackoverflow.com/a/56724489/5992714

Questions est un doublon possible de Pourquoi le comportement de setTimeout (0) et setImmediate () est-il indéfini lorsqu'il est utilisé dans le module principal?

Humain
la source
1
Veuillez ne pas publier exactement la même réponse à deux questions. Si les questions sont différentes, adaptez la réponse à chacune. S'ils sont identiques, signalez ou votez pour en fermer un comme un doublon.
Tom Zych
@TomZych a noté.
humain
0

Je pense que la réponse de Navya S n'est pas correcte, voici mon code de test:

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);

Les explications sont ici

笑笑 十年
la source
0

setTimeout (fn, 0) peut être utilisé pour empêcher le navigateur de se figer lors d'une mise à jour massive. par exemple dans websocket.onmessage, vous pouvez avoir des changements html, et si les messages continuent à arriver, le navigateur peut se figer lors de l'utilisation de setImmidiate

Lior Goldemberg
la source
0

Pour les comprendre profondément, veuillez une fois passer par les phases de la boucle d'événements.

SetImmediate: Il est exécuté dans la phase de "vérification". La phase de contrôle est appelée après la phase d'E / S.

SetTimeOut: Il est exécuté dans la phase "timer". La phase de temporisation est la première phase mais est appelée après la phase d' E / S ainsi que la phase de vérification .

Pour obtenir la sortie d'une manière déterministe, cela dépendra de la phase de la boucle d'événements; en conséquence, nous pouvons utiliser la fonction sur deux.

kanika sharma
la source
-4

utilisez setImmediate () pour ne pas bloquer la boucle d'événements. Le rappel s'exécutera sur la prochaine boucle d'événements, dès que celle en cours sera terminée.

utilisez setTimeout () pour contrôler les délais. La fonction s'exécutera après le délai spécifié. Le délai minimum est de 1 milliseconde.

Andras
la source