Exécutez la fonction setInterval sans délai la première fois


341

C'est là un moyen de configurer la setIntervalméthode de javascript pour exécuter la méthode immédiatement, puis s'exécute avec le minuteur


4
Pas nativement cependant. Vous pouvez essayer d'appeler functionune fois puis de faire lesetInterval()
Mrchief

Réponses:


519

Il est plus simple d'appeler directement la fonction directement la première fois:

foo();
setInterval(foo, delay);

Cependant, il y a de bonnes raisons d'éviter setInterval- en particulier dans certaines circonstances, toute une série d' setIntervalévénements peuvent arriver immédiatement les uns après les autres sans aucun retard. Une autre raison est que si vous voulez arrêter la boucle, vous devez appeler explicitement, clearIntervalce qui signifie que vous devez vous souvenir du handle renvoyé par l' setIntervalappel d' origine .

Donc, une autre méthode consiste à se foodéclencher pour les appels suivants en utilisant à la setTimeoutplace:

function foo() {
   // do stuff
   // ...

   // and schedule a repeat
   setTimeout(foo, delay);
}

// start the cycle
foo();

Cela garantit qu'il y a au moins un intervalle delayentre les appels. Cela facilite également l'annulation de la boucle si nécessaire - vous n'appelez simplement pas setTimeoutlorsque votre condition de fin de boucle est atteinte.

Mieux encore, vous pouvez envelopper tout cela dans une expression de fonction immédiatement invoquée qui crée la fonction, qui se rappelle ensuite comme ci-dessus et démarre automatiquement la boucle:

(function foo() {
    ...
    setTimeout(foo, delay);
})();

qui définit la fonction et démarre le cycle d'un seul coup.


5
Pourquoi préférez-vous setTimeout?
Sanghyun Lee

19
@Sangdol, car il garantit que les événements de la minuterie ne se "cumulent" pas s'ils ne sont pas traités. Dans certaines circonstances, toute une série d' setIntervalévénements peut arriver immédiatement les uns après les autres sans aucun retard.
Alnitak

8
Il devrait y avoir une sorte de test qui ne vous permet pas de publier sur la pile lorsque vous êtes fatigué
James

3
Comment arrêter la fonction si j'utilise la setTimeoutméthode?
Gaurav Bhor

6
@DaveMunger non, car ce n'est pas vraiment récursif - c'est seulement "pseudo-récursif". Les appels "récursifs" ne se produisent pas jusqu'à ce que le navigateur revienne à la boucle d'événement, moment auquel la pile d'appels a été complètement déroulée.
Alnitak

210

Je ne sais pas si je vous comprends bien, mais vous pourriez facilement faire quelque chose comme ça:

setInterval(function hello() {
  console.log('world');
  return hello;
}(), 5000);

Il y a évidemment un certain nombre de façons de procéder, mais c'est la façon la plus concise à laquelle je peux penser.


16
C'est une bonne réponse car c'est une fonction nommée qui s'exécute immédiatement et se retourne également. Exactement ce que je cherchais.
jmort253

41
Certainement une solution intéressante, mais susceptible de semer la confusion chez les personnes qui liront à l'avenir.
Deepak Joy

4
Vous n'avez pas besoin de lui donner un nom «bonjour». Vous pouvez à la place retourner arguments.callee et avoir la même chose avec une fonction anonyme
JochenJung

10
@JochenJung arguments.calleen'est pas disponible en mode strict ES5
Alnitak

3
C'est le genre de code Javascript qui confondra la plupart des nouveaux programmeurs JS venus d'autres langues. Écrivez un tas de trucs comme ça si votre entreprise n'a pas beaucoup de personnel JS et que vous voulez la sécurité de l'emploi.
Ian

13

Je suis tombé sur cette question en raison du même problème, mais aucune des réponses n'aide si vous devez vous comporter exactement comme setInterval()mais avec la seule différence que la fonction est appelée immédiatement au début.

Voici ma solution à ce problème:

function setIntervalImmediately(func, interval) {
  func();
  return setInterval(func, interval);
}

L'avantage de cette solution:

  • le code existant en utilisant setIntervalpeut facilement être adapté par substitution
  • fonctionne en mode strict
  • il fonctionne avec les fonctions et fermetures nommées existantes
  • vous pouvez toujours utiliser la valeur de retour et la transmettre à clearInterval()plus tard

Exemple:

// create 1 second interval with immediate execution
var myInterval = setIntervalImmediately( _ => {
        console.log('hello');
    }, 1000);

// clear interval after 4.5 seconds
setTimeout( _ => {
        clearInterval(myInterval);
    }, 4500);

Pour être effronté, si vous avez vraiment besoin d'utiliser, setIntervalvous pouvez également remplacer l'original setInterval. Par conséquent, aucun changement de code n'est requis lors de l'ajout avant votre code existant:

var setIntervalOrig = setInterval;

setInterval = function(func, interval) {
    func();
    return setIntervalOrig(func, interval);
}

Pourtant, tous les avantages énumérés ci-dessus s'appliquent ici, mais aucune substitution n'est nécessaire.


Je préfère cette solution à la setTimeoutsolution car elle renvoie un setIntervalobjet. Pour éviter d'appeler des fonctions qui sont peut-être plus tard dans le code et donc indéfinies à l'heure actuelle, j'encapsule le premier appel de fonction dans une setTimeoutfonction comme celle-ci: setTimeout(function(){ func();},0);La première fonction est ensuite appelée après le cycle de traitement en cours, qui est également immédiatement , mais est plus d'erreur prouvée.
pensan

8

Vous pouvez encapsuler setInterval()une fonction qui fournit ce comportement:

function instantGratification( fn, delay ) {
    fn();
    setInterval( fn, delay );
}

... puis utilisez-le comme ceci:

instantGratification( function() {
    console.log( 'invoked' );
}, 3000);

5
Je pense que vous devriez retourner ce que setInterval renvoie. C'est parce que sinon vous ne pouvez pas utiliser clearInterval.
Henrik R

5

Voici un wrapper pour le faire si vous en avez besoin:

(function() {
    var originalSetInterval = window.setInterval;

    window.setInterval = function(fn, delay, runImmediately) {
        if(runImmediately) fn();
        return originalSetInterval(fn, delay);
    };
})();

Définissez le troisième argument de setInterval sur true et il s'exécutera pour la première fois immédiatement après l'appel de setInterval:

setInterval(function() { console.log("hello world"); }, 5000, true);

Ou omettez le troisième argument et il conservera son comportement d'origine:

setInterval(function() { console.log("hello world"); }, 5000);

Certains navigateurs prennent en charge des arguments supplémentaires pour setInterval que ce wrapper ne prend pas en compte; Je pense que ceux-ci sont rarement utilisés, mais gardez cela à l'esprit si vous en avez besoin.


9
Remplacer les fonctions natives du navigateur est terrible car il peut briser d'autres codes coexistants lorsque les spécifications changent. En fait, setInterval a actuellement plus de paramètres: developer.mozilla.org/en-US/docs/Web/API/WindowTimers/…
Áxel Costas Pena

2

Car quelqu'un a besoin d'amener l'extérieur thiscomme s'il s'agissait d'une fonction de flèche.

(function f() {
    this.emit("...");
    setTimeout(f.bind(this), 1000);
}).bind(this)();

Si les déchets ci-dessus vous dérangent, vous pouvez faire une fermeture à la place.

(that => {
    (function f() {
        that.emit("...");
        setTimeout(f, 1000);
    })();
})(this);

Ou peut-être envisagez d'utiliser le @autobinddécorateur en fonction de votre code.


1

Je proposerai d'appeler les fonctions dans l'ordre suivant

var _timer = setInterval(foo, delay, params);
foo(params)

Vous pouvez également passer _timerau foo, si vous le souhaitez à clearInterval(_timer)une certaine condition

var _timer = setInterval(function() { foo(_timer, params) }, delay);
foo(_timer, params);

Pourriez-vous expliquer cela plus en profondeur?
Polyducks

vous réglez la minuterie à partir du deuxième appel, pour la première fois vous appelez directement le fn directement.
Jayant Varshney

1

Voici une version simple pour les novices sans tous les ennuis. Il déclare simplement la fonction, l'appelle, puis démarre l'intervalle. C'est tout.

//Declare your function here
function My_Function(){
  console.log("foo");
}    

//Call the function first
My_Function();

//Set the interval
var interval = window.setInterval( My_Function, 500 );


1
C'est exactement ce que fait la réponse acceptée dans la première ligne. Comment cette réponse ajoute-t-elle quelque chose de nouveau?
Dan Dascalescu

La réponse acceptée poursuit en disant de ne pas faire cela. Ma réponse à la réponse acceptée explique pourquoi c'est toujours une méthode valide. L'OP demande spécifiquement d'appeler la fonction setInterval lors de son premier appel, mais la réponse acceptée se détourne pour parler des avantages de setTimeout.
Polyducks

0

Pour résoudre ce problème, j'exécute la fonction une première fois après le chargement de la page.

function foo(){ ... }

window.onload = function() {
   foo();
};

window.setInterval(function()
{
    foo(); 
}, 5000);

0

Il existe un package npm pratique appelé firstInterval (divulgation complète, c'est le mien).

La plupart des exemples ici n'incluent pas la gestion des paramètres, et changer les comportements par défaut de setIntervaltout grand projet est mauvais. De la documentation:

Ce modèle

setInterval(callback, 1000, p1, p2);
callback(p1, p2);

est identique à

firstInterval(callback, 1000, p1, p2);

Si vous êtes de la vieille école dans le navigateur et que vous ne voulez pas de dépendance, c'est un simple copier-coller du code.


0

// YCombinator
function anonymous(fnc) {
  return function() {
    fnc.apply(fnc, arguments);
    return fnc;
  }
}

// Invoking the first time:
setInterval(anonymous(function() {
  console.log("bar");
})(), 4000);

// Not invoking the first time:
setInterval(anonymous(function() {
  console.log("foo");
}), 4000);
// Or simple:
setInterval(function() {
  console.log("baz");
}, 4000);

Ok, c'est tellement complexe, alors, permettez-moi de le dire plus simplement:

function hello(status ) {    
  console.log('world', ++status.count);
  
  return status;
}

setInterval(hello, 5 * 1000, hello({ count: 0 }));


C'est largement trop conçu.
Polyducks

0

Vous pouvez définir un temps de retard initial très petit (par exemple 100) et le régler sur le temps de retard souhaité dans la fonction:

var delay = 100;

function foo() {
  console.log("Change initial delay-time to what you want.");
  delay = 12000;
  setTimeout(foo, delay);
}


-2

Il y a un problème avec l'appel asynchrone immédiat de votre fonction, car setTimeout / setInterval standard a un délai minimal d'environ plusieurs millisecondes même si vous le définissez directement sur 0. Cela est dû à un travail spécifique au navigateur.

Un exemple de code avec un REAL zéro retard qui fonctionne dans Chrome, Safari, Opera

function setZeroTimeout(callback) {
var channel = new MessageChannel();
channel.port1.onmessage = callback;
channel.port2.postMessage('');
}

Vous pouvez trouver plus d'informations ici

Et après le premier appel manuel, vous pouvez créer un intervalle avec votre fonction.


-10

en fait le plus rapide est de faire

interval = setInterval(myFunction(),45000)

cela appellera ma fonction, puis le fera toutes les 45 secondes, ce qui est différent de faire

interval = setInterval(myfunction, 45000)

qui ne l'appellera pas, mais le planifiera seulement


Où est-ce que tu as trouvé ça?
Ken Sharp

2
Cela ne fonctionne que si se myFunction()retourne. Au lieu de cela, modifier chaque fonction à appeler setIntervalest une meilleure approche pour boucler setIntervalune fois comme les autres réponses le proposent.
Jens Wirth
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.