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

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() .


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”.


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

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>

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!


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.


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.


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


@ 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');
});


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.


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.


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

1

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

function executeWithDelay(anotherFunction) {
    setTimeout(anotherFunction, delayInMilliseconds);
}

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

-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());

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.