Poczekaj 5 sekund przed wykonaniem następnej linii

312

Ta funkcja poniżej nie działa tak, jak chcę; będąc nowicjuszem w JS nie wiem, dlaczego.

Muszę poczekać 5 sekund, zanim sprawdzę, czy tak newStatejest -1.

Obecnie nie czeka, po prostu sprawdza od razu.

function stateChange(newState) {
  setTimeout('', 5000);

  if(newState == -1) {
    alert('VIDEO HAS STOPPED');
  }
}
płatek kopii
źródło

Odpowiedzi:

323

Musisz umieścić swój kod w funkcji zwrotnej, którą udostępniasz setTimeout:

function stateChange(newState) {
    setTimeout(function () {
        if (newState == -1) {
            alert('VIDEO HAS STOPPED');
        }
    }, 5000);
}

Każdy inny kod zostanie wykonany natychmiast.

Joseph Silber
źródło
4
Główny problem polega na tym, że w niektórych przypadkach (szczególnie w testach) jest to żałośnie nieodpowiednie. Co zrobić, jeśli musisz spać przez 500 ms przed powrotem z funkcji, na przykład w celu symulacji wolnego żądania asynchronicznego HTTP?
A.Grandt
14
Jeśli przez „testowanie” rozumiesz testy jednostkowe: środowisko testowe powinno mieć możliwość uruchamiania testów asynchronicznych. Jeśli masz na myśli testowanie ręczne: karta Sieć Chrome ma menu rozwijane Ograniczanie, które symuluje wolne żądania.
Joseph Silber,
1
co jeśli opracuję rozszerzenie chrome, a ostatnia obliczona wartość we wstrzykiwanym skrypcie powinna dać mi wynik; i potrzebuję opóźnień?
mirek
183

Naprawdę nie powinieneś tego robić , prawidłowe użycie limitu czasu jest właściwym narzędziem dla problemu PO i każdej innej okazji, w której po prostu chcesz coś uruchomić po pewnym czasie. Joseph Silber pokazał to dobrze w swojej odpowiedzi. Jeśli jednak w jakimś nieprodukcyjnym przypadku naprawdę chcesz zawiesić główny wątek na pewien czas, zrobi to.

function wait(ms){
   var start = new Date().getTime();
   var end = start;
   while(end < start + ms) {
     end = new Date().getTime();
  }
}

Z wykonaniem w formie:

console.log('before');
wait(7000);  //7 seconds in milliseconds
console.log('after');

Przybyłem tutaj, ponieważ budowałem prosty przypadek testowy do sekwencjonowania kombinacji operacji asynchronicznych wokół długotrwałych operacji blokujących (tj. Kosztownej manipulacji DOM) i to jest moja symulowana operacja blokowania. Dobrze pasuje do tej pracy, więc pomyślałem, że opublikuję ją dla każdego, kto przyjedzie tutaj z podobnym przypadkiem użycia. Mimo to tworzy obiekt Date () w pętli while, co może bardzo przytłoczyć GC, jeśli będzie działać wystarczająco długo. Ale nie mogę wystarczająco podkreślić, jest to odpowiednie tylko do testowania, do budowania jakiejkolwiek faktycznej funkcjonalności, którą powinieneś odnieść do odpowiedzi Josepha Silbera.

Mikrofon
źródło
7
To nie zatrzyma wykonywania javascript.
Terry Lin
23
@TerryLin Spróbuj uruchomić.
Mic
6
Zasadniczo marnujesz czas procesora. To nie jest czekanie, ponieważ nie przełączasz wątku w tryb uśpienia, umożliwiając procesorowi głównemu skupienie się na innych zadaniach.
Kyordhel,
6
@Gzork Uśpienie wątku jest tylko jednym sposobem na wdrożenie funkcji oczekiwania i niestety nie jest dostępne w kontekście javascript po stronie klienta. Jeśli jednak uważasz, że inne zadania asynchroniczne w kliencie zostaną ukończone podczas jego działania, to oczywiście go nie testowałeś. Chociaż użyłbym go w głównym wątku, zestawiłem skrzypce ilustrujące, że nawet jeśli jest to wywoływane przez setTimeout w pierwszej kolejności, nadal zakłóca inne zdarzenia asynchroniczne jsfiddle.net/souv51v3/1 - znajdziesz nawet Samo okno JSFiddle przestaje odpowiadać po zakończeniu.
Mic.
1
Straszne rozwiązanie IMHO - powoduje, że procesor jest „śpiący”. Właściwy sposób na sen to async / czekaj także na tę odpowiedź stackoverflow.com/questions/951021/... lub Etienne's.
David Simic
162

Oto rozwiązanie wykorzystujące nową składnię async / await .

Sprawdź obsługę przeglądarki, ponieważ jest to nowa funkcja wprowadzona w ECMAScript 6.

Funkcja użyteczności:

const delay = ms => new Promise(res => setTimeout(res, ms));

Stosowanie:

const yourFunction = async () => {
  await delay(5000);
  console.log("Waited 5s");

  await delay(5000);
  console.log("Waited an additional 5s");
};

Zaletą tego podejścia jest to, że sprawia, że ​​Twój kod wygląda i zachowuje się jak kod synchroniczny.

Etienne Martin
źródło
Nie potrzebujesz ECMAScript 6: Jeśli używasz już obietnic do załadowania asynchronicznego i po prostu chcesz naśladować jedną część łańcucha długo, możesz dodać tę funkcję wait () do łańcucha.
Dovev Hefetz
2
To naprawdę najlepsza odpowiedź z nową składnią. Miałem problemy z użyciem powyższego rozwiązania wait ().
pianoman102
36

Nie powinieneś po prostu próbować zatrzymać 5 sekund w javascript. To nie działa w ten sposób. Możesz zaplanować uruchomienie funkcji kodu za 5 sekund od teraz, ale musisz umieścić kod, który chcesz uruchomić później w funkcji, a reszta kodu po tej funkcji będzie nadal działać natychmiast.

Na przykład:

function stateChange(newState) {
    setTimeout(function(){
        if(newState == -1){alert('VIDEO HAS STOPPED');}
    }, 5000);
}

Ale jeśli masz taki kod:

stateChange(-1);
console.log("Hello");

console.log()Oświadczenie będzie działać natychmiast. Nie będzie czekać, aż upłynie limit czasu wstateChange() funkcji. Nie można po prostu wstrzymać wykonywania javascript na określony czas.

Zamiast tego każdy kod, który chcesz uruchomić, musi znajdować się wewnątrz setTimeout() funkcji zwrotnej (lub wywoływanej z tej funkcji).

Jeśli spróbujesz „wstrzymać” przez zapętlenie, to zasadniczo zawiesisz interpreter Javascript na pewien czas. Ponieważ JavaScript uruchamia kod tylko w jednym wątku, podczas zapętlania nic innego nie może zostać uruchomione (nie można wywoływać żadnych innych programów obsługi zdarzeń). Pętla oczekująca na zmianę jakiejś zmiennej nigdy nie zadziała, ponieważ żaden inny kod nie może działać, aby zmienić tę zmienną.

jfriend00
źródło
31
Nie można po prostu wstrzymać wykonywania javascript na określony czas . Myślę, że to znaczy, że nie powinien, ponieważ może (jeśli chcesz powiesić)var t = new Date().getTime(); while (new Date().getTime() < t + millisecondsToLockupBrowser);
Joseph Silber
9
@JosephSilber - OK, możesz to zrobić, ale w praktyce to nie działa, ponieważ wiele przeglądarek wyświetli okno dialogowe z informacją, że skrypt przestał reagować ORAZ to straszne wrażenia dla użytkownika i niekorzystne dla żywotności baterii, a strona jest zawiesił się, robiąc to i ... To byłoby złe.
jfriend00
12
No oczywiście , że byłoby straszne, i nikt nie powinien nigdy nigdy nigdy nigdy nigdy nigdy zrobić. Po prostu nie mogłem się oprzeć mojemu wewnętrznemu „dobrze” . Przepraszam.
Joseph Silber
31

Jeśli korzystasz z funkcji asynchronicznej , możesz to zrobić w jednym wierszu:

console.log(1);
await new Promise(resolve => setTimeout(resolve, 3000)); // 3 sec
console.log(2);

Zauważ , że jeśli celem jest NodeJS, użycie tego będzie bardziej wydajne (jest to predefiniowana, obiecana funkcja setTimeout):

await setTimeout[Object.getOwnPropertySymbols(setTimeout)[0]](3000) // 3 sec
Shl
źródło
Jaka jest różnica między tymi dwiema implementacjami?
EAzevedo
1
Obecnie nie ma różnicy. Ale jeśli w pewnym momencie węzeł zdecyduje się uczynić go szybszym / bezpieczniejszym / bardziej wydajnym, z góry użyjesz wersji węzła js. Chociaż gotowość jest bardziej prawdopodobna dla większości ludzi, w takim przypadku lepiej użyć pierwszego sposobu.
Shl
Dziękuję Ci. Twoja odpowiedź rozwiązała problem, z którym borykam się już od trzech dni. Dzięki.
EAzevedo
8

Spróbuj tego:

//the code will execute in 1 3 5 7 9 seconds later
function exec() {
    for(var i=0;i<5;i++) {
        setTimeout(function() {
            console.log(new Date());   //It's you code
        },(i+i+1)*1000);
    }
}
Steve Jiang
źródło
7

Najlepszym sposobem na utworzenie takiej funkcji jest czekanie w milisekundach, ta funkcja będzie czekać na milisekundy podane w argumencie:

function waitSeconds(iMilliSeconds) {
    var counter= 0
        , start = new Date().getTime()
        , end = 0;
    while (counter < iMilliSeconds) {
        end = new Date().getTime();
        counter = end - start;
    }
}

Jitendra Pal - JP
źródło
3

Na podstawie Josepha Silber za odpowiedź , chciałbym zrobić to tak, że nieco bardziej ogólne.

Miałbyś swoją funkcję (stwórzmy ją na podstawie pytania):

function videoStopped(newState){
   if (newState == -1) {
       alert('VIDEO HAS STOPPED');
   }
}

I możesz mieć funkcję oczekiwania:

function wait(milliseconds, foo, arg){
    setTimeout(function () {
        foo(arg); // will be executed after the specified time
    }, milliseconds);
}

Na koniec miałbyś:

wait(5000, videoStopped, newState);

To rozwiązanie, wolałbym nie używać argumentów w funkcji oczekiwania (aby mieć tylko foo();zamiast foo(arg);), ale tak jest na przykład.

Sylhare
źródło
3

To rozwiązanie pochodzi z dokumentacji React Native dotyczącej kontroli odświeżania :

function wait(timeout) {
    return new Promise(resolve => {
        setTimeout(resolve, timeout);
    });
}

Aby zastosować to do pytania PO, możesz użyć tej funkcji w koordynacji z await:

await wait(5000);
if (newState == -1) {
    alert('Done');
}
bearacuda13
źródło
1

Możesz dodać opóźnienie, wprowadzając niewielkie zmiany w funkcji (asynchronizuj i czekaj).

const add5SecondsDelay = () => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('5 seconds');
    }, 50000);
  });
}

async function asyncFunctionCall() {

  console.log("stpe-1"); 
  const result = await add5SecondsDelay ();
  console.log("step-2 after 5 seconds delay"); 

}

asyncFunctionCall();
p.durga shankar
źródło
-2

using angularjs:

$timeout(function(){
if(yourvariable===-1){
doSomeThingAfter5Seconds();
}
},5000)
Dr. Abbos
źródło
-2

Utwórz nową funkcję Js

function sleep(delay) {
        var start = new Date().getTime();
        while (new Date().getTime() < start + delay);
      }

Wywołaj funkcję, jeśli chcesz opóźnić wykonanie. Użyj wartości milisekund w int dla wartości opóźnienia.

####Some code
 sleep(1000);
####Next line
Madushanka Sampath
źródło
3
To zużyje zbyt wiele zasobów.
awavi
-2

Użyłem go do uruchamiania gier komputerowych z Edge lub IE. I automatycznie zamyka IE Edge po 7 sekundach.

Firefox i Google Chrome nie mogą być używane do uruchamiania gier w ten sposób.

<html<body>
<a href="E:\game\game.exe" name="game" onmouseout="waitclose(7000);"> game
<img src="game.jpg" width="100%" height="97%" ></a>
<script>
function waitclose(ms){
 var start = new Date().getTime();var end=start;
 while(end < start + ms) {end = new Date().getTime();}
window.open('', '_self', ''); window.close();
}
</script>
</body></html>
użytkownik4565320
źródło