Warten Sie 5 Sekunden, bevor Sie die nächste Zeile ausführen

313

Diese Funktion funktioniert nicht so, wie ich es möchte. Als JS-Neuling kann ich nicht herausfinden, warum.

Ich brauche es, um 5 Sekunden zu warten, bevor ich prüfe, ob das newStateist -1.

Derzeit wartet es nicht, es überprüft nur sofort.

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

  if(newState == -1) {
    alert('VIDEO HAS STOPPED');
  }
}
Copyflake
quelle

Antworten:

323

Sie müssen Ihren Code in die Rückruffunktion eingeben, die Sie bereitstellen an setTimeout:

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

Jeder andere Code wird sofort ausgeführt.

Joseph Silber
quelle
4
Das Hauptproblem ist, dass dies in einigen Fällen (insbesondere beim Testen) absolut unzureichend ist. Was ist, wenn Sie 500 ms schlafen müssen, bevor Sie von der Funktion zurückkehren, um beispielsweise eine langsame asynchrone http-Anforderung zu simulieren ?
A. Grandt
14
Wenn Sie mit "Testen" Unit-Tests meinen: Ihr Test-Framework sollte eine Möglichkeit haben, asynchrone Tests auszuführen. Wenn Sie manuelles Testen meinen: Auf der Registerkarte "Netzwerk" von Chrome befindet sich eine Dropdown-Liste "Drosselung", mit der langsame Anforderungen simuliert werden können.
Joseph Silber
1
Was ist, wenn ich eine Chrome-Erweiterung entwickle und der zuletzt ausgewertete Wert im injizierten Skript das Ergebnis liefert? und ich brauche ein paar Verzögerungen?
Mirek
184

Sie sollten dies wirklich nicht tun . Die korrekte Verwendung des Timeouts ist das richtige Werkzeug für das Problem des OP und für jede andere Gelegenheit, bei der Sie nach einer bestimmten Zeit nur etwas ausführen möchten. Joseph Silber hat dies in seiner Antwort gut demonstriert. Wenn Sie jedoch in einem Fall außerhalb der Produktion den Haupt-Thread wirklich für einen bestimmten Zeitraum aufhängen möchten, ist dies ausreichend.

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

Mit Ausführung in der Form:

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

Ich bin hier angekommen, weil ich einen einfachen Testfall für die Sequenzierung einer Mischung aus asynchronen Operationen um lang laufende Blockierungsoperationen (dh teure DOM-Manipulation) erstellt habe. Dies ist meine simulierte Blockierungsoperation. Es passt gut zu diesem Job, also dachte ich, ich poste es für alle anderen, die mit einem ähnlichen Anwendungsfall hier ankommen. Trotzdem wird ein Date () -Objekt in einer while-Schleife erstellt, was den GC sehr überfordern kann, wenn er lange genug ausgeführt wird. Aber ich kann nicht genug betonen, dies ist nur zum Testen geeignet, um eine tatsächliche Funktionalität aufzubauen, die Sie auf Joseph Silbers Antwort verweisen sollten.

Mic
quelle
7
Dies wird die Ausführung von Javascript nicht stoppen.
Terry Lin
23
@ TerryLin Versuchen Sie es auszuführen.
Mic
6
Im Grunde verschwenden Sie also CPU-Zeit. Das ist keine Wartezeit, da Sie den Thread nicht in den Ruhemodus versetzen, sodass sich der Hauptprozessor auf andere Aufgaben konzentrieren kann.
Kyordhel
6
@Gzork Thread-Schlaf ist nur eine Möglichkeit, eine Wartefunktion zu implementieren, und sie ist im Kontext von clientseitigem Javascript leider nicht verfügbar. Wenn Sie jedoch glauben, dass andere asynchrone Aufgaben im Client während der Ausführung ausgeführt werden, haben Sie sie offensichtlich nicht getestet. Obwohl ich es im Hauptthread verwenden würde, habe ich eine Geige zusammengestellt, die veranschaulicht, dass selbst wenn dies zunächst über ein setTimeout aufgerufen wird, andere asynchrone Ereignisse unterbrochen werden. Jsfiddle.net/souv51v3/1 - Sie finden sogar die Das JSFiddle-Fenster selbst reagiert während des Abschlusses nicht mehr.
Mic
1
Schreckliche Lösung IMHO - hog CPU, während es "schläft". Der richtige Weg zu schlafen ist über async / warte ala diese Antwort stackoverflow.com/questions/951021/… oder Etienne's.
David Simic
163

Hier ist eine Lösung mit der neuen Syntax async / await .

Überprüfen Sie unbedingt die Browserunterstützung, da dies eine neue Funktion ist, die mit ECMAScript 6 eingeführt wurde.

Dienstprogrammfunktion:

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

Verwendungszweck:

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

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

Der Vorteil dieses Ansatzes besteht darin, dass Ihr Code wie synchroner Code aussieht und sich verhält.

Etienne Martin
quelle
Sie benötigen ECMAScript 6 nicht: Wenn Sie bereits Versprechen verwenden, um das asynchrone Laden durchzuführen, und nur einen Teil der Kette nachahmen möchten, der lange dauert, können Sie diese wait () - Funktion zur Kette hinzufügen.
Dovev Hefetz
2
Dies ist wirklich die beste Antwort mit der neuen Syntax. Ich hatte Probleme mit der Verwendung der wait () -Lösung oben.
Pianoman102
36

Sie sollten nicht nur versuchen, 5 Sekunden in Javascript anzuhalten. Das funktioniert nicht so. Sie können festlegen, dass eine Codefunktion in 5 Sekunden ausgeführt wird. Sie müssen jedoch den Code, den Sie später ausführen möchten, in eine Funktion einfügen, und der Rest Ihres Codes nach dieser Funktion wird sofort weiter ausgeführt.

Zum Beispiel:

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

Aber wenn Sie Code wie diesen haben:

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

Die console.log()Anweisung wird sofort ausgeführt. Es wird nicht warten, bis das Timeout in derstateChange() Funktion . Sie können die Ausführung von Javascript nicht einfach für einen festgelegten Zeitraum anhalten.

Stattdessen muss sich jeder Code, für den Sie Verzögerungen ausführen möchten, innerhalb von befinden setTimeout() Rückruffunktion befinden (oder von dieser Funktion aufgerufen werden).

Wenn Sie versucht haben, durch Schleifen "anzuhalten", haben Sie den Javascript-Interpreter im Wesentlichen für einen bestimmten Zeitraum "aufgehängt". Da Javascript Ihren Code nur in einem einzigen Thread ausführt, kann beim Schleifen nichts anderes ausgeführt werden (keine anderen Ereignishandler können aufgerufen werden). Das Schleifen, das darauf wartet, dass sich eine Variable ändert, funktioniert also nie, da kein anderer Code ausgeführt werden kann, um diese Variable zu ändern.

jfriend00
quelle
31
Sie können die Ausführung von Javascript nicht einfach für einen festgelegten Zeitraum anhalten . Ich denke du meinst du solltest nicht, da du kannst (wenn du dich aufhängen willst):var t = new Date().getTime(); while (new Date().getTime() < t + millisecondsToLockupBrowser);
Joseph Silber
9
@JosephSilber - OK, gut, Sie könnten das tun, aber in der Praxis, wenn nicht so viele Browser funktionieren, wird ein Dialogfeld angezeigt, das besagt, dass ein Skript nicht mehr reagiert UND es eine schreckliche Benutzererfahrung ist und die Akkulaufzeit beeinträchtigt und die Seite schlecht ist dabei aufgehängt und ... Das wäre schlecht.
jfriend00
12
Nun natürlich , das wäre schrecklich, und niemand sollte jemals jemals jemals jemals jemals jemals das tun. Ich konnte meinem inneren "eigentlich" nicht widerstehen . Es tut uns leid.
Joseph Silber
31

Wenn Sie sich in einer asynchronen Funktion befinden , können Sie dies einfach in einer Zeile tun:

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

Beachten Sie , wenn das Ziel NodeJS ist, ist es effizienter, dies zu verwenden (es ist eine vordefinierte versprochene setTimeout-Funktion):

await setTimeout[Object.getOwnPropertySymbols(setTimeout)[0]](3000) // 3 sec
Shl
quelle
Was ist der Unterschied zwischen den beiden Implementierungen?
EAzevedo
1
Derzeit gibt es keinen Unterschied. Wenn sich der Knoten jedoch irgendwann dafür entscheidet, ihn schneller / sicherer / effizienter zu machen, verwenden Sie die Version des Knotens im Voraus. Obwohl die Lesbarkeit für die meisten Menschen eher der Schlüsselfaktor ist, sollten Sie in diesem Fall den ersten Weg besser nutzen.
Shl
Danke dir. Ihre Antwort hat ein Problem gelöst, mit dem ich bereits seit drei Tagen konfrontiert bin. Vielen Dank.
EAzevedo
8

Versuche dies:

//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
quelle
7

Der beste Weg, um eine solche Funktion für das Warten in Millisekunden zu erstellen, ist, dass diese Funktion auf die im Argument angegebenen Millisekunden wartet:

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
quelle
3

Basierend auf Joseph Silbers Antwort würde ich es so machen, ein bisschen allgemeiner.

Sie hätten Ihre Funktion (lassen Sie uns eine basierend auf der Frage erstellen):

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

Und Sie könnten eine Wartefunktion haben:

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

Am Ende hätten Sie:

wait(5000, videoStopped, newState);

Das ist eine Lösung, ich würde lieber keine Argumente in der Wartefunktion verwenden (nur foo();statt haben foo(arg);), aber das ist für das Beispiel.

Sylhare
quelle
3

Diese Lösung stammt aus der Dokumentation von React Native für eine Aktualisierungssteuerung :

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

Um dies auf die Frage des OP anzuwenden, können Sie diese Funktion in Abstimmung mit await:

await wait(5000);
if (newState == -1) {
    alert('Done');
}
bearacuda13
quelle
1

Sie können Verzögerungen hinzufügen, indem Sie kleine Änderungen an Ihrer Funktion vornehmen (asynchron und warten).

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
quelle
-2

mit anglejs:

$timeout(function(){
if(yourvariable===-1){
doSomeThingAfter5Seconds();
}
},5000)
Dr. Abbos
quelle
-2

Erstellen Sie eine neue Js-Funktion

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

Rufen Sie die Funktion auf, wenn Sie die Ausführung verzögern möchten. Verwenden Sie Millisekunden in int für den Verzögerungswert.

####Some code
 sleep(1000);
####Next line
Madushanka Sampath
quelle
3
Das wird zu viel Ressourcen verbrauchen.
Awavi
-2

Ich habe es verwendet, um PC-Spiele von Edge oder IE auszuführen. Und es schließt IE Edge nach 7 Sekunden selbst.

Firefox und Google Chrome können nicht verwendet werden, um Spiele auf diese Weise zu starten.

<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>
user4565320
quelle