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

Jorge
źródło
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.

Alnitak
źródło
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ć.

chjj
źródło
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.

Jens Wirth
źródło
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);
użytkownik113716
źródło
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.

Mahn
źródło
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.

Константин Ван
źródło
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);
Jayant Varshney
źródło
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 );

Polyducks
źródło
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);
Dario
źródło
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.

jimm101
źródło
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 }));

NSD
źródło
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);
}

reo_yamanaka
źródło
-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.

Xe-Xe
źródło
-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

Hertzel Armengol
źródło
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