web-dev-qa-db-fra.com

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

Quelle est la différence entre ces deux, et quand vais-je utiliser l'un sur l'autre?

53
Shlomi Schwartz

setTimeout est simplement comme appeler la fonction une fois le délai écoulé. Chaque fois qu'une fonction est appelée, elle n'est pas exécutée immédiatement, mais mise en file d'attente de sorte qu'elle soit exécutée une fois que tous les gestionnaires d'événements en cours d'exécution et actuellement en file d'attente ont terminé. setTimeout (, 0) signifie essentiellement exécuter après que toutes les fonctions en cours de la file d'attente actuelle soient exécutées. 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, le rappel est exécuté. Il les met immédiatement en file d'attente après le dernier gestionnaire d'E/S, un peu comme process.nextTick. Donc c'est plus rapide.

De plus (setTimeout, 0) sera lent car il vérifiera la minuterie au moins une fois avant de l'exécuter. Parfois, il peut être deux fois plus lent. Voici un repère.

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

Sortie

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 si setTimeout est appelée deux fois moins souvent que les autres. 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 juste comme c'est dans le navigateur. Cela peut ne pas convenir au serveur (pensez pourquoi j'ai utilisé benchmark.js pas setTimeout).

54
user568109

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:

Les rappels setImmediate sont appelés une fois que les rappels de la file d'attente d'E/S sont terminés ou qu'ils ont expiré. Les rappels setImmediate sont placés dans la file d'attente de vérification, qui sont traités après la file d'attente d'E/S.

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

9
Aman Gupta

setImmediate () sert à planifier l'exécution immédiate du rappel après les rappels d'événements I/O et avant setTimeout et setInterval.

setTimeout () est destiné à planifier l'exécution d'un rappel ponctuel après un délai de plusieurs 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 le même ... même si le document actuel indique que "Pour planifier l'exécution" immédiate "du rappel après les rappels d'événements I/O et avant setTimeout et setInterval. ..

Résultat..

setTimeout 

setImmediate

Si vous emballez 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);
6
Navya S

utilisez toujours setImmediate, sauf si vous êtes vraiment sûr d'avoir besoin de setTimeout(,0) (mais je ne peux même pas imaginer pourquoi). Le rappel setImmediate sera presque toujours exécuté avant setTimeout(,0), sauf lorsqu’il sera appelé dans le premier tick et dans le rappel setImmediate.

2
vkurchatkin

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

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

0
bigdatamann

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

0
Lior Goldemberg

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

0
笑笑十年