Wykonaj skrypt po określonym opóźnieniu za pomocą JavaScript

189

Czy istnieje jakakolwiek metoda JavaScript podobna do jQuery delay()lub wait()(aby opóźnić wykonanie skryptu o określony czas)?

Niyaz
źródło

Odpowiedzi:

189

Istnieją następujące:

setTimeout(function, milliseconds);

funkcja, którą można przekazać, po upływie której funkcja zostanie wykonana.

Zobacz: Metoda oknasetTimeout() .

Abhinav
źródło
3
To nie jest wykonywane wyrażenie, to funkcja. Odpowiedź @Mariusa to ilustruje.
pedrofurla
117
to nie jest opóźnienie, to widelec. Opóźnienie powinno działać w tym samym wątku.
DragonLord
13
Spowoduje to natychmiastowe wykonanie funkcji Aby „pracować” (asynchronicznie) należy podać: setTimeout (function () {MethodToCall ();}, 1000);
Bernoulli IT,
6
Chcę podkreślić, że mówimy o JavaScript; przywoływanie „wątków” lub tego, że powinno działać „synchronicznie”, może być prawdziwe pod względem technicznym i semantycznym, ale tak naprawdę nie mieści się w kontekście JavaScript, biorąc pod uwagę, że naprawdę nie ma sposobu na osiągnięcie opóźnienia za pomocą żadnej z tych metod (nie „ t tworzyć „wątki” w JS, tak jak robisz to w innych językach). Ponadto nie zostanie to natychmiast wykonane, function_referencechyba że zostanie to uwzględnione (). To znaczyfunction_reference To tylko to - odniesienie; przekazanie function_reference()wywołałoby funkcję natychmiast.
Danny Bullis
237

Aby dodać do tego, o czym wszyscy inni mówili setTimeout: jeśli chcesz wywołać funkcję z parametrem w przyszłości, musisz skonfigurować anonimowe wywołania funkcji.

Musisz przekazać funkcję jako argument, aby mogła zostać wywołana później. W efekcie oznacza to brak nawiasów za nazwą. Następujące wywołają alert natychmiast i wyświetli „Hello world”:

var a = "world";
setTimeout(alert("Hello " + a), 2000);

Aby to naprawić, możesz albo wpisać nazwę funkcji (jak zrobiła to Flubba), albo możesz użyć funkcji anonimowej. Jeśli musisz przekazać parametr, musisz użyć funkcji anonimowej.

var a = "world";
setTimeout(function(){alert("Hello " + a)}, 2000);
a = "Stack Overflow";

Ale jeśli uruchomisz ten kod, zauważysz, że po 2 sekundach wyskakujące okienko powie „Hello Stack Overflow”. Jest tak, ponieważ wartość zmiennej a zmieniła się w ciągu tych dwóch sekund. Aby po dwóch sekundach powiedzieć „Witaj świecie”, musisz użyć następującego fragmentu kodu:

function callback(a){
    return function(){
        alert("Hello " + a);
    }
}
var a = "world";
setTimeout(callback(a), 2000);
a = "Stack Overflow";

Poczeka 2 sekundy, a następnie wyskakujące okienko „Hello world”.

Marius
źródło
37

Tylko trochę rozwinąć ... Możesz wykonać kod bezpośrednio w setTimeoutwywołaniu, ale jak mówi @patrick , zwykle przypisujesz funkcję wywołania zwrotnego, tak jak to. Czas to milisekundy

setTimeout(func, 4000);
function func() {
    alert('Do stuff here');
}
Polsonby
źródło
27

Jeśli naprawdę chcesz mieć funkcję blokującą (synchroniczną) delay(cokolwiek), dlaczego nie zrobić czegoś takiego:

<script type="text/javascript">
    function delay(ms) {
        var cur_d = new Date();
        var cur_ticks = cur_d.getTime();
        var ms_passed = 0;
        while(ms_passed < ms) {
            var d = new Date();  // Possible memory leak?
            var ticks = d.getTime();
            ms_passed = ticks - cur_ticks;
            // d = null;  // Prevent memory leak?
        }
    }

    alert("2 sec delay")
    delay(2000);
    alert("done ... 500 ms delay")
    delay(500);
    alert("done");
</script>
Mario Werner
źródło
2
Trudność tego rozwiązania polega na tym, że aktywnie wykorzystuje procesor, co prowadzi do zwiększonego zużycia energii i zmniejszenia zasobów dostępnych dla innych wątków / procesów (np. Innych kart, innych programów). Natomiast tryb uśpienia tymczasowo wstrzymuje korzystanie z zasobów systemowych przez wątek.
ramcdougal
1
lepiej użyć Date.now () zamiast nowej Date () i nie myśl o przeciekach pamięci
WayFarer
1
Oczywiście jest to procesor intensywny, ale do szybkiego i brudnego testowania działa
Maris B.
Chcę wersję, która nie blokuje wątku, więc mogę odświeżyć DOM przed delaying (aby odpowiedzieć na to pytanie ). Czy jest na to jakiś sposób?
Gui Imamura
3
Bardziej zwarta procedura: opóźnienie funkcji (ms) {var start_time = Date.now (); while (Date.now () - czas_początkowy <ms); }
Duke
15

Musisz użyć setTimeout i przekazać mu funkcję zwrotną. Powodem, dla którego nie możesz korzystać ze snu w javascript, jest to, że w międzyczasie blokowałbyś całą stronę. Niezły plan. Skorzystaj z modelu zdarzeń Javascript i bądź szczęśliwy. Nie walcz z tym!

Patrick
źródło
2
Nadal byłby użyteczny do celów testowych. Na przykład opóźnienie przesłania formularza na kilka sekund w celu oceny zmian strony przed wysłaniem nowego żądania HTTP.
rushinge
1
@ rushinge następnie ustaw oddzwanianie, aby przesłać formularz i wyłączyć domyślny formularz przesyłania
Populus
1
Zły pomysł, aby zostawić link jako kod ... ponieważ teraz nie działa.
Emmet Arries
1
Albo wiesz, mógłbym to naprawić.
Patrick
14

Możesz także użyć funkcji window.setInterval (), aby wielokrotnie uruchamiać kod w regularnych odstępach czasu.

rcoup
źródło
2
setInterval () nie powinien być używany zamiast tego powinien używać setTimeout
Paul
9
setTimeout()robi to raz, setInterval()robi to wielokrotnie. Jeśli chcesz, aby Twój kod był uruchamiany co 5 sekund, setInterval()jest przeznaczony dla zadania.
rcoup
11

Aby dodać wcześniejsze komentarze, chciałbym powiedzieć, co następuje:

setTimeout()Funkcji w JavaScript nie wstrzymać wykonanie skryptu per se, ale jedynie informuje kompilator do wykonania kodu kiedyś w przyszłości.

Nie ma funkcji, która może faktycznie wstrzymać wykonywanie wbudowane w JavaScript. Możesz jednak napisać własną funkcję, która robi coś w rodzaju bezwarunkowej pętli, dopóki czas nie zostanie osiągnięty, używając Date()funkcji i dodając potrzebny przedział czasu.

narasi
źródło
11

Jeśli potrzebujesz tylko przetestować opóźnienie, możesz użyć tego:

function delay(ms) {
   ms += new Date().getTime();
   while (new Date() < ms){}
}

A jeśli chcesz opóźnić o 2 sekundy, robisz:

delay(2000);

Może nie być najlepszy do produkcji. Więcej na ten temat w komentarzach

Christoffer
źródło
@ U2744 SNOWFLAKE Czy możesz starać się być bardziej precyzyjnym w swoim komentarzu
Christoffer
1
Cóż, jest to zajęta pętla, która rozładuje baterie laptopów i innych urządzeń mobilnych, a prawdopodobnie również uniemożliwi reagowanie (lub nawet wyświetlanie) interfejsu użytkownika.
Ry-
@ U2744SNOWFLAKE Ma sens. Zaktualizowałem odpowiedź, do czego użyłem tej funkcji :)
Christoffer
2
Działa wystarczająco dobrze w fazie rozwoju, aby uzyskać szybkie i brudne (i tymczasowe) rozwiązanie.
HumanInDisguise
5

dlaczego nie możesz umieścić kodu za obietnicą? (wpisany na czubku głowy)

new Promise(function(resolve, reject) {
  setTimeout(resolve, 2000);
}).then(function() {
  console.log('do whatever you wanted to hold off on');
});

Al Joslin
źródło
5

Prosta odpowiedź brzmi:

setTimeout(
    function () {
        x = 1;
    }, 1000);

Powyższa funkcja czeka 1 sekundę (1000 ms), a następnie ustawia x na 1. Oczywiście jest to przykład; możesz zrobić wszystko, co chcesz w ramach funkcji anonimowej.

Luca
źródło
4

Naprawdę podobało mi się wyjaśnienie Mauriusa (najwyższa pozytywna odpowiedź) z trzema różnymi metodami wywoływania setTimeout.

W moim kodzie chcę automatycznie nawigować do poprzedniej strony po zakończeniu zdarzenia zapisu AJAX. Zakończenie zdarzenia zapisywania ma niewielką animację w CSS, co wskazuje, że zapis był udany.

W moim kodzie znalazłem różnicę między pierwszymi dwoma przykładami:

setTimeout(window.history.back(), 3000);

Ten nie czeka na przekroczenie limitu czasu - funkcja back () jest wywoływana prawie natychmiast, bez względu na to, jaki numer wprowadzę dla opóźnienia.

Jednak zmieniając to na:

setTimeout(function() {window.history.back()}, 3000);

To robi dokładnie to, na co liczyłem.

Nie jest to specyficzne dla operacji back (), to samo dzieje się z alert(). Zasadniczo w przypadku alert()zastosowanego w pierwszym przypadku czas opóźnienia jest ignorowany. Kiedy odrzucam wyskakujące okienko, animacja dla CSS jest kontynuowana.

Dlatego poleciłbym drugą lub trzecią metodę, którą opisuje, nawet jeśli używasz wbudowanych funkcji i nie używasz argumentów.

Doug
źródło
1

Miałem kilka komend ajax, które chciałem uruchomić z opóźnieniem pomiędzy nimi. Oto prosty przykład jednego ze sposobów, aby to zrobić. Jestem przygotowany na rozerwanie na strzępy ze względu na moje niekonwencjonalne podejście. :)

//  Show current seconds and milliseconds
//  (I know there are other ways, I was aiming for minimal code
//  and fixed width.)
function secs()
{
    var s = Date.now() + ""; s = s.substr(s.length - 5);
  return s.substr(0, 2) + "." + s.substr(2);
}

//  Log we're loading
console.log("Loading: " + secs());

//  Create a list of commands to execute
var cmds = 
[
    function() { console.log("A: " + secs()); },
    function() { console.log("B: " + secs()); },
    function() { console.log("C: " + secs()); },
    function() { console.log("D: " + secs()); },
    function() { console.log("E: " + secs()); },
  function() { console.log("done: " + secs()); }
];

//  Run each command with a second delay in between
var ms = 1000;
cmds.forEach(function(cmd, i)
{
    setTimeout(cmd, ms * i);
});

// Log we've loaded (probably logged before first command)
console.log("Loaded: " + secs());

Możesz skopiować blok kodu i wkleić go do okna konsoli i zobaczyć coś takiego:

Loading: 03.077
Loaded: 03.078
A: 03.079
B: 04.075
C: 05.075
D: 06.075
E: 07.076
done: 08.076
JohnnyIV
źródło
1

Najprostszym sposobem na wywołanie funkcji z opóźnieniem jest:

function executeWithDelay(anotherFunction) {
    setTimeout(anotherFunction, delayInMilliseconds);
}
Jackkobec
źródło
0

funkcja opóźnienia:

/**
 * delay or pause for some time
 * @param {number} t - time (ms)
 * @return {Promise<*>}
 */
const delay = async t => new Promise(resolve => setTimeout(resolve, t));

użycie asyncfunkcji wewnętrznej :

await delay(1000);
Zuhair Taha
źródło
-1

Jak już powiedziano, setTimeout jest najbezpieczniejszym zakładem.
Ale czasami nie można oddzielić logiki do nowej funkcji, wówczas można użyć funkcji Date.now (), aby uzyskać milisekundy i samodzielnie wykonać opóźnienie ....

function delay(milisecondDelay) {
   milisecondDelay += Date.now();
   while(Date.now() < milisecondDelay){}
}

alert('Ill be back in 5 sec after you click OK....');
delay(5000);
alert('# Im back # date:' +new Date());

JavaSheriff
źródło