Uruchom funkcję setInterval za pierwszym razem bez opóźnienia


341

Jest to sposób na skonfigurowanie setIntervalmetody javascript do natychmiastowego wykonania metody, a następnie wykonania z timerem


4
Ale nie natywnie. Możesz spróbować zadzwonić functionraz, a następnie wykonaćsetInterval()
— Mrchief

Odpowiedzi:


519

Najłatwiej jest po prostu wywołać tę funkcję bezpośrednio za pierwszym razem:

foo();
setInterval(foo, delay);

Istnieją jednak dobre powody, aby tego unikać setInterval- w szczególności w niektórych okolicznościach cały szereg setIntervalzdarzeń może nadejść natychmiast po sobie bez żadnych opóźnień. Innym powodem jest to, że jeśli chcesz zatrzymać pętlę, musisz jawnie wywołać, clearIntervalco oznacza, że ​​musisz pamiętać uchwyt zwrócony z pierwotnego setIntervalwywołania.

Zatem alternatywną metodą jest foowyzwalanie się dla kolejnych wywołań za pomocą setTimeout:

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

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

// start the cycle
foo();

Gwarantuje to, że między rozmowami jest co najmniej przerwa delay. Ułatwia także anulowanie pętli w razie potrzeby - po prostu nie dzwoniszsetTimeout gdy warunek zakończenia pętli zostanie osiągnięty.

Co więcej, możesz zawinąć to wszystko w bezpośrednio wywoływane wyrażenie funkcyjne, które tworzy funkcję, która następnie wywołuje się ponownie jak wyżej i automatycznie uruchamia pętlę:

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

który definiuje funkcję i rozpoczyna cykl od razu.


5
Dlaczego wolisz setTimeout?
— Sanghyun Lee

19
@Sangdol, ponieważ zapewnia, że ​​zdarzenia czasowe nie będą się „układać”, jeśli pozostaną nieprzetworzone. W niektórych okolicznościach cały szereg setIntervalzdarzeń może nadejść natychmiast po sobie bez żadnych opóźnień.
— Alnitak

8
Powinien istnieć rodzaj testu, który nie pozwoli Ci pisać na stosie, gdy jesteś zmęczony
— James

3
Jak zatrzymać funkcję, jeśli użyję setTimeoutmetody?
— Gaurav Bhor,

6
@DaveMunger nie, ponieważ nie jest tak naprawdę rekurencyjny - to tylko „pseudo-rekurencyjny”. Wywołania „rekurencyjne” nie zdarzają się, dopóki przeglądarka nie powróci do pętli zdarzeń, w którym to momencie stos wywołań został całkowicie rozwinięty.
— Alnitak,

210

Nie jestem pewien, czy rozumiem cię poprawnie, ale możesz łatwo zrobić coś takiego:

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

Jest na to oczywiście wiele sposobów, ale to najbardziej zwięzły sposób, jaki mogę wymyślić.


16
To fajna odpowiedź, ponieważ jest to nazwana funkcja, która wykonuje się natychmiast, a także sama się zwraca. Dokładnie tego szukałem.
— jmort253

41
Zdecydowanie fajne rozwiązanie, ale może powodować zamieszanie u osób czytających w przyszłości.
— Deepak Joy,

4
Nie musisz nadawać mu nazwy „cześć”. Zamiast tego możesz zwrócić arguments.callee i mieć to samo z anonimową funkcją
— JochenJung 24.09.15

10
@JochenJung arguments.calleenie jest dostępny w ścisłym trybie ES5
— Alnitak,

3
Jest to rodzaj kodu JavaScript, który dezorientuje większość nowych programistów JS, którzy pochodzą z innych języków. Napisz wiele takich rzeczy, jeśli Twoja firma nie ma zbyt wielu pracowników JS, a chcesz bezpieczeństwa pracy.
— Ian

13

Natknąłem się na to pytanie z powodu tego samego problemu, ale żadna z odpowiedzi nie pomaga, jeśli musisz zachowywać się dokładnie tak samo,setInterval() ale z jedynym różnicą, że funkcja nazywa się natychmiast na początku.

Oto moje rozwiązanie tego problemu:

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

Zaletą tego rozwiązania:

  • istniejący kod za pomocą setInterval może być łatwo dostosowany przez podstawienie
  • działa w trybie ścisłym
  • działa z istniejącymi nazwanymi funkcjami i zamknięciami
  • nadal możesz użyć wartości zwracanej i przekazać ją clearInterval()później

Przykład:

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

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

Aby być zuchwałym, jeśli naprawdę potrzebujesz użyć, setIntervalmożesz również zastąpić oryginał setInterval. Dlatego podczas dodawania tego kodu przed istniejącym kodem nie jest wymagana zmiana kodu:

var setIntervalOrig = setInterval;

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

Nadal obowiązują tutaj wszystkie wymienione wyżej korzyści, ale nie jest wymagana zamiana.


Wolę to rozwiązanie od setTimeoutrozwiązania, ponieważ zwraca setIntervalobiekt. Aby uniknąć wywoływania funkcji, które mogą być później w kodzie i dlatego nie są zdefiniowane w chwili obecnej, zawijam pierwsze wywołanie funkcji w setTimeoutfunkcji takiej jak ta: setTimeout(function(){ func();},0);Pierwsza funkcja jest następnie wywoływana po bieżącym cyklu przetwarzania, który jest również natychmiastowy , ale jest więcej potwierdzonych błędów.
— pensan

8

Możesz owinąć setInterval()funkcję, która zapewnia takie zachowanie:

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

... użyj tego w następujący sposób:

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

5
Myślę, że powinieneś zwrócić to, co zwraca setInterval. Wynika to z tego, że w przeciwnym razie nie można użyć clearInterval.
— Henrik R

5

Oto opakowanie na całkiem fajny, jeśli go potrzebujesz:

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

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

Ustaw trzeci argument setInterval na true, a po raz pierwszy uruchomi się natychmiast po wywołaniu setInterval:

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

Lub pomiń trzeci argument, a on zachowa swoje pierwotne zachowanie:

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

Niektóre przeglądarki obsługują dodatkowe argumenty dla setInterval, których to opakowanie nie bierze pod uwagę; Myślę, że są one rzadko używane, ale pamiętaj o tym, jeśli ich potrzebujesz.


9
Zastępowanie natywnych funkcji przeglądarki jest straszne, ponieważ może zmienić inny współistniejący kod, gdy zmieniają się specyfikacje. W rzeczywistości setInterval ma obecnie więcej parametrów: developer.mozilla.org/en-US/docs/Web/API/WindowTimers/…
— Áxel Costas Pena

2

Ktoś musi wprowadzić to, co zewnętrzne, thisjakby to była funkcja strzałki.

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

Jeśli przeszkadzają ci powyższe śmieci, możesz zamiast tego zrobić zamknięcie.

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

A może rozważyć korzystanie z @autobinddekorator w zależności od kodu.


1

Zasugeruję wywołanie funkcji w następującej kolejności

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

Możesz również przekazać _timerfoo, jeśli chcesz clearInterval(_timer)pod pewnym warunkiem

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

Czy możesz to wyjaśnić bardziej szczegółowo?
— Polyducks

ustawiasz licznik czasu od drugiego połączenia, po raz pierwszy dzwonisz bezpośrednio do fn.
— Jayant Varshney

1

Oto prosta wersja dla nowicjuszy bez całego zamieszania. Po prostu deklaruje funkcję, wywołuje ją, a następnie rozpoczyna interwał. Otóż ​​to.

//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
Właśnie to robi zaakceptowana odpowiedź w pierwszych kilku wierszach. Jak ta odpowiedź dodaje coś nowego?
— Dan Dascalescu

Przyjęta odpowiedź mówi dalej, aby tego nie robić. Moja odpowiedź na zaakceptowaną odpowiedź wyjaśnia, dlaczego wciąż jest to poprawna metoda. OP w szczególności prosi o wywołanie funkcji setInterval przy pierwszym wywołaniu, ale zaakceptowana odpowiedź przekierowuje, aby mówić o zaletach setTimeout.
— Polyducks

0

Aby rozwiązać ten problem, uruchamiam funkcję po raz pierwszy po załadowaniu strony.

function foo(){ ... }

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

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

0

Jest wygodny pakiet npm o nazwie firstInterval (pełne ujawnienie, to moje).

Wiele przykładów tutaj nie obejmuje obsługi parametrów, a zmiana domyślnych zachowań setIntervalw każdym dużym projekcie jest zła. Z dokumentów:

Ten wzór

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

jest identyczny z

firstInterval(callback, 1000, p1, p2);

Jeśli jesteś starą szkołą w przeglądarce i nie chcesz zależności, możesz łatwo wyciąć i wkleić kod.


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, to jest takie skomplikowane, więc powiem bardziej prościej:

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

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


Jest to znacznie przerobione.
— Polyducks

0

Możesz ustawić bardzo mały początkowy czas opóźnienia (np. 100) i ustawić go na żądany czas opóźnienia w funkcji:

var delay = 100;

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


-2

Wystąpił problem z natychmiastowym asynchronicznym wywołaniem funkcji, ponieważ standardowy setTimeout / setInterval ma minimalny limit czasu około kilku milisekund, nawet jeśli bezpośrednio ustawisz na 0. Jest to spowodowane pracą przeglądarki.

Przykład kodu z PRAWDZIWYM opóźnieniem zerowym, które działa w Chrome, Safari, Opera

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

Więcej informacji znajdziesz tutaj

Po pierwszym ręcznym wywołaniu możesz utworzyć interwał za pomocą swojej funkcji.


-10

w rzeczywistości najszybsze jest do zrobienia

interval = setInterval(myFunction(),45000)

wywoła to moją funkcję, a następnie zrobi to agaian co 45 sekund, co różni się od działania

interval = setInterval(myfunction, 45000)

który tego nie nazwie, ale tylko zaplanuj


Skąd to masz?
— Ken Sharp

2
Działa to tylko wtedy, myFunction()gdy sam się zwraca. Zamiast tego modyfikowanie każdej wywoływanej przez setIntervalnią funkcji jest lepszym podejściem do zawijania, setIntervalgdy proponowane są inne odpowiedzi.
— Jens Wirth
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.