Was ist die JavaScript-Version von sleep ()?

2335

Gibt es eine bessere Möglichkeit, eine sleepin JavaScript zu erstellen als die folgende pausecompFunktion ( von hier übernommen )?

function pausecomp(millis)
{
    var date = new Date();
    var curDate = null;
    do { curDate = new Date(); }
    while(curDate-date < millis);
}

Dies ist kein Duplikat von Sleep in JavaScript - Verzögerung zwischen Aktionen ; Ich möchte einen echten Schlaf mitten in einer Funktion und keine Verzögerung, bevor ein Teil des Codes ausgeführt wird.

fmsf
quelle
4
Es ist in der Mitte einer Weile zu setzen, wenn ich setTimeout benutze, wird das while weiterhin mehr setTimeouts verarbeiten und in die Warteschlange stellen, die schließlich zur gleichen Zeit ausgeführt werden und ein bisschen Parallelität zwischen sich herstellen
fmsf
159
Dies ist eine schreckliche Lösung - Sie werden Verarbeitungszyklen zerkauen, ohne etwas zu tun.
17 vom 26.
12
Der einzige Zweck für einen Schlaf ist das Abrufen oder Warten auf einen Rückruf - setInterval und setTimeout machen beide besser als dies.
Annakata
1
Wahrscheinlich können Sie mit dem Continuation-Passing-Stil in JavaScript tun, was Sie wollen. Schauen Sie sich diesen Artikel an.
Ognyan Dimitrov

Antworten:

2561

Update 2017 - 2019

Seit 2009, als diese Frage gestellt wurde, hat sich JavaScript erheblich weiterentwickelt. Alle anderen Antworten sind jetzt veraltet oder zu kompliziert. Hier ist die aktuelle Best Practice:

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function demo() {
  console.log('Taking a break...');
  await sleep(2000);
  console.log('Two seconds later, showing sleep in a loop...');

  // Sleep in loop
  for (let i = 0; i < 5; i++) {
    if (i === 3)
      await sleep(2000);
    console.log(i);
  }
}

demo();

Das ist es. await sleep(<duration>).

Oder als Einzeiler:

await new Promise(r => setTimeout(r, 2000));

Beachten Sie, dass,

  1. awaitkann nur in Funktionen ausgeführt werden, denen das asyncSchlüsselwort vorangestellt ist , oder in einigen Umgebungen (z. B. der Chrome DevTools-Konsole oder Runkit) auf der obersten Ebene Ihres Skripts.
  2. awaitpausiert nur die aktuelle asyncFunktion

Zwei neue JavaScript-Funktionen haben beim Schreiben dieser "Schlaf" -Funktion geholfen:

Kompatibilität

Wenn aus irgendeinem seltsamen Grund , den Sie verwenden Knoten älter als 7 (was erreicht hat Ende des Lebens ), oder alte Browser zielen, async/ awaitnoch über verwendet werden Babel (ein Werkzeug , das wird transpile JavaScript + neue Funktionen in plain old JavaScript) mit dem transform-async-to-generatorPlugin.

Dan Dascalescu
quelle
5
Tolles Zeug hier. Ich frage mich, wie sich dies auf die "aktiven" / "inaktiven" Zustände der modernen Browser auswirkt oder damit zusammenhängt, nachdem JS den "Schlaf" -Modus aufgerufen hat. Kann der Browser den Ruhezustand wie erwartet für allgemeine JS blockieren, um ihn später abzurufen, wenn er "aktiv" wird, oder hat er ein anderes Verhalten?
Andre Canilho
18
Was ist die aktuelle Browserunterstützung dafür? Ich würde die vorherigen Lösungen nicht als "veraltet" betrachten, bis diese Lösung von der überwiegenden Mehrheit der Browser oder zumindest allen gängigen unterstützt wird. Im Gegenteil, ich würde diese Lösung für interessant, aber unbrauchbar / unpraktisch halten, bis sie breite Unterstützung findet.
Alvin Thompson
74
Dies ist kein "richtiger Schlaf" und beantwortet die Frage nicht. Die Person, die gefragt hat, hat klar zwischen stackoverflow.com/questions/758688/sleep-in-javascript und seiner Frage unterschieden. Im realen Schlaf kann kein anderer Code ausgeführt werden (außer in einem anderen Thread). Diese Antwort ist gut für die andere Frage.
niry
4
@jacroe - der Transpiler behandelt Pfeilfunktionen sowie Async / Warten (was dazu führen würde, dass IE ohnehin Blut
erbricht
11
@niry JavaScript ist eine Single-Threaded-Sprache und eignet sich nicht für "echten" Schlaf, da es auf demselben Thread wie die Benutzeroberfläche ausgeführt wird und nicht reagierende Webseiten verursachen würde.
Patrick Roberts
849

(Siehe die aktualisierte Antwort für 2016 )

Ich denke, es ist völlig vernünftig, eine Aktion ausführen zu wollen, zu warten und dann eine andere Aktion auszuführen. Wenn Sie es gewohnt sind, in Multithread-Sprachen zu schreiben, haben Sie wahrscheinlich die Idee, die Ausführung für einen festgelegten Zeitraum zu ermöglichen, bis Ihr Thread aufwacht.

Das Problem hierbei ist, dass JavaScript ein ereignisbasiertes Single-Thread-Modell ist. Während es in einem bestimmten Fall schön sein kann, den gesamten Motor einige Sekunden warten zu lassen, ist dies im Allgemeinen eine schlechte Praxis. Angenommen, ich wollte Ihre Funktionen nutzen, während ich meine eigenen schreibe? Wenn ich Ihre Methode aufrief, froren alle meine Methoden ein. Wenn JavaScript den Ausführungskontext Ihrer Funktion irgendwie beibehalten, irgendwo speichern, dann zurückbringen und später fortfahren könnte, könnte der Ruhezustand eintreten, aber das wäre im Grunde ein Threading.

Sie bleiben also ziemlich bei dem, was andere vorgeschlagen haben - Sie müssen Ihren Code in mehrere Funktionen aufteilen.

Ihre Frage ist also eine falsche Wahl. Es gibt keine Möglichkeit, so zu schlafen, wie Sie es möchten, und Sie sollten auch nicht die von Ihnen vorgeschlagene Lösung verfolgen.

Ben Flynn
quelle
45
Dies ist überhaupt keine richtige Antwort. Wenn Javascript keine Schlaffunktion hat, liegt dies nur daran, dass ECMAScript diese nicht benötigt. Es ist eine Designentscheidung der für das Design von Javascript zuständigen Stelle. Es hätte gemacht werden können, dass die Javascript-Laufzeit eine bestimmte Zeit wartet, bevor die nächste Codezeile ausgeführt wird, aber es wurde ausgewählt, dies nicht zu tun.
Didier A.
5
Ein Schlaf kann perfekt in JavaScript implementiert werden, allerdings nicht mit Echtzeitgenauigkeit. Immerhin ist es ein ereignisbasiertes System. Wenn asynchrone Anrufe abgeschlossen sind, wird ein Ereignis ausgelöst. Ich sehe keinen Grund, warum dies nicht möglich sein kann, wenn ein sleep () ausgegeben wird, nach dem das Steuerelement an den Browser zurückgegeben wird, bis das Sleeping beendet ist, und das Steuerelement an die aufrufende Funktion zurückgibt. Und ja, ich stimme auch zu, dass manchmal Schlafen praktisch ist, besonders wenn Entwickler, BEVOR Sie das Design so stark vermasselt haben, dass SIE keinen anderen Ausweg haben als das komplette Refactoring, für das Sie keine Zeit haben
Lawrence
Versuchen Sie Hypnotic, das dieser Idee folgt: coolwanglu.github.io/hypnotic/web/demo.html
Tezcat
4
Javascript Single-Threaded zu nennen, ist ein Mythos. Obwohl es technisch korrekt sein mag, verhält es sich funktional wie eine Multithread-Sprache. Das Simulieren eines Fork () ist trivial einfach, und obwohl Yield () nicht wirklich implementierbar ist, können Sie ziemlich nahe kommen, indem Sie Shared / Semaphore im Shared Memory verwenden. Für den durchschnittlichen Programmierer ist es sinnvoll, ihn als Multithreading zu behandeln. Der technische Name ist nur für die Entwickler der Sprache von Bedeutung.
Benubird
8
Ich stimme zu, warum sleep()dies in JS nicht möglich ist und dass es die meiste Zeit bessere Möglichkeiten gibt, Dinge zu tun. Aber ich würde immer noch die Art und Weise, wie der Motor alle Dinge zusammenhält, als Konstruktionsfehler betrachten. Es gibt keinen Grund, warum die Sprache keine sleep()Funktion haben könnte, die auf ein bestimmtes Skript, eine bestimmte Seite oder eine bestimmte Funktion beschränkt ist, ohne dass die Engine die CPU überlastet und die App wie ein Verrückter einfriert. Es ist 2015 und Sie sollten nicht in der Lage sein, einen ganzen Webbrowser mit zum Absturz zu bringen while(1). Wir haben Flash für solche Dinge.
Beejor
660

In JavaScript schreibe ich jede Funktion neu, damit sie so schnell wie möglich beendet werden kann. Sie möchten, dass der Browser wieder die Kontrolle hat, damit er Ihre DOM-Änderungen vornehmen kann.

Jedes Mal, wenn ich mitten in meiner Funktion schlafen wollte, überarbeitete ich die Verwendung von a setTimeout().

Bearbeiten

Die berüchtigte Schlaf- oder Verzögerungsfunktion in jeder Sprache wird viel diskutiert. Einige werden sagen, dass es immer ein Signal oder einen Rückruf geben sollte, um eine bestimmte Funktionalität auszulösen, andere werden argumentieren, dass manchmal ein beliebiger Moment der Verzögerung nützlich ist. Ich sage, dass jeder seine eigene und eine Regel niemals etwas in dieser Branche diktieren kann.

Das Schreiben einer Schlaffunktion ist einfach und mit JavaScript Promises noch benutzerfreundlicher:

// sleep time expects milliseconds
function sleep (time) {
  return new Promise((resolve) => setTimeout(resolve, time));
}

// Usage!
sleep(500).then(() => {
    // Do something after the sleep!
});
gsamaras
quelle
190
Zum Abschluss. function foobar(el) { setTimeout(function() { foobar_cont(el); }, 5000); }
Chaos
68
ok, und was ist, wenn der Code nicht für die Verwendung auf einer Webseite vorgesehen ist?
Eugenio Miró
10
@ EugenioMiró Wenn der Code nicht für die Verwendung auf einer Webseite vorgesehen ist, lassen Sie das Objektmodell des Hosts eine Schlafmethode implementieren. - Ich denke, die Frage richtet sich an das DOM, das Javascript ausgesetzt ist, das auf Webseiten ausgeführt wird.
BrainSlugs83
31
@Nosredna ja, wir verstehen, wie man asynchrone Anrufe tätigt, das hilft uns nicht beim Schlafen (). Ich möchte, dass meine Anrufe in einer bestimmten Reihenfolge getätigt werden und die Daten wieder in einer bestimmten Reihenfolge vorliegen. Ich bin 5 Level tief in einer for-Schleife. Ich möchte die Ausführung blockieren. Eine echte Schlafmethode würde den Browser nicht "verlangsamen", die Kontrolle über den Browser und alle anderen Threads, die CPU-Zeit benötigen, während er noch blockiert, zurückgeben.
BrainSlugs83
382
Dies ist keine Antwort auf die Frage.
TMS
303

Nur für Debug / Dev poste ich dies, wenn es für jemanden nützlich ist

Interessantes, in Firebug (und wahrscheinlich auch in anderen js-Konsolen) passiert nichts, nachdem Sie die Eingabetaste gedrückt haben, nur nach der angegebenen Schlafdauer (...)

function sleepFor( sleepDuration ){
    var now = new Date().getTime();
    while(new Date().getTime() < now + sleepDuration){ /* do nothing */ } 
}

Anwendungsbeispiel:

function sleepThenAct(){ sleepFor(2000); console.log("hello js sleep !"); }
StephaneAG
quelle
36
Dies ist keine Antwort. Es ist genau das gleiche wie der Code in der Frage, nur etwas kürzer.
Stich
16
Wirklich beschäftigt zu warten? In JS? Für Sekunden? Wenn ich dabei eine Website erwische, wird diese blockiert.
Mafu
34
@mafu Deshalb heißt es only for debug/dev... rolleyes
xDaizu
12
TUN SIE DAS NIEMALS. Dadurch erreicht die CPU 100% des von ihr ausgeführten Kerns und blockiert ihn.
Noego
3
Dies ist nützlich und möglicherweise die EINZIGE Möglichkeit, in einer Javascript-Befehlszeilenanwendung zu schlafen, da async / await nicht hilfreich ist.
Wheezil
177

Ich stimme den anderen Postern zu, ein geschäftiger Schlaf ist nur eine schlechte Idee.

SetTimeout verzögert jedoch nicht die Ausführung, sondern führt die nächste Zeile der Funktion unmittelbar nach dem Einstellen des Timeouts aus, nicht nach Ablauf des Timeouts, sodass nicht dieselbe Aufgabe ausgeführt wird, die ein Sleep ausführen würde.

Der Weg, dies zu tun, besteht darin, Ihre Funktion in vor und nach Teilen aufzuteilen.

function doStuff()
{
  //do some things
  setTimeout(continueExecution, 10000) //wait ten seconds before continuing
}

function continueExecution()
{
   //finish doing things after the pause
}

Stellen Sie sicher, dass Ihre Funktionsnamen immer noch genau beschreiben, was jedes Teil tut (IE GatherInputThenWait und CheckInput anstelle von funcPart1 und funcPart2).

Bearbeiten

Mit dieser Methode wird der Zweck erreicht, die von Ihnen festgelegten Codezeilen erst nach Ablauf Ihrer Zeitüberschreitung auszuführen, während die Steuerung weiterhin an den Client-PC zurückgegeben wird, um alle anderen Warteschlangen auszuführen.

Weitere Bearbeitung

Wie in den Kommentaren erwähnt, wird dies absolut NICHT in einer Schleife funktionieren. Sie könnten ein ausgefallenes (hässliches) Hacking durchführen, damit es in einer Schleife funktioniert, aber im Allgemeinen führt dies nur zu katastrophalem Spaghetti-Code.

DevinB
quelle
12
Ja. Dies wird schwierig, wenn Sie eine Schleife oder sogar eine verschachtelte Schleife haben. Sie müssen Ihre for-Schleifen aufgeben und stattdessen Zähler haben.
Nosredna
Touché. Ich meine, es wäre immer noch möglich, aber in diesem Fall hässlich und hackig. Sie könnten auch einige statische boolesche Zustandsvariablen verwenden, aber das ist auch ziemlich hackisch.
DevinB
2
-1 dafür. Auch dies beantwortet die Frage nicht. Dies ist eher eine Antwort auf eine Frage wie "So führen Sie eine Funktion asynchron aus", die sich stark von "So blockieren Sie eine Codeausführung" unterscheidet.
Deepak GM
6
@Nosredna Nein, du würdest einen Verschluss verwenden. Zum Beispiel: function foo(index) { setTimeout(function() { foo_continue(index); }, 10000); }und for(var X = 0; X < 3;X++) { foo(X); }- der Wert von X wird übergeben foo, der dann unter dem Namen wiederverwendet wird, indexwenn er foo_continueschließlich aufgerufen wird.
Izkata
2
@Alexander Natürlich, denn mit setTimeout () soll verhindert werden, dass der Browser blockiert, indem der Code asychron ausgeführt wird. Wenn Sie das console.log()Innere foo_continue()in die setTimeout-Version einfügen, erhalten Sie das gleiche Ergebnis.
Izkata
132

Aus Liebe zu $ ​​DEITY machen Sie bitte keine Funktion zum Warten auf viel zu tun. setTimeoutund setIntervalmach alles was du brauchst.

var showHide = document.getElementById('showHide');
setInterval(() => {
    showHide.style.visibility = "initial";
    setTimeout(() => {
        showHide.style.visibility = "hidden"
    }, 1000);
    ;
}, 2000);   
<div id="showHide">Hello! Goodbye!</div>

Alle zwei Sekunden wird der Text eine Sekunde lang ausgeblendet. Dies zeigt, wie Sie mit setInterval und setTimeout jede Sekunde Text ein- und ausblenden.

Philip Rego
quelle
3
Nun, nicht alles: setInterval macht einen viel besseren Eindruck von Umfragen.
Annakata
3
Was würde dieser Code in der JavaScript-Engine nicht zurückhalten?
Deniz Dogan
10
Es sei denn, Sie möchten, dass der Schlaf synchron ist. In diesem Fall ist dies eine vollständig gültige Frage.
Aaron Dufour
36
Ich denke, viele von uns vergessen möglicherweise, dass JavaScript keine reine Browsersprache ist. Dieser Typ erstellt möglicherweise ein Node-Befehlszeilenprogramm, das eine kurze Pause erfordert, ohne dass alle mit setTimeout verbundenen Probleme mit dem variablen Gültigkeitsbereich behandelt werden müssen.
Phil LaNasa
3
@PhilLaNasa: Wenn der syntaktische Abschluss immer noch Angst macht, muss man sich ernsthaft anschnallen und durch Knoten 101 arbeiten.
Chaos
113

Ich weiß, dass dies eine alte Frage ist, aber wenn Sie (wie ich) Javascript mit Rhino verwenden, können Sie ...

try
{
  java.lang.Thread.sleep(timeInMilliseconds);
}
catch (e)
{
  /*
   * This will happen if the sleep is woken up - you might want to check
   * if enough time has passed and sleep again if not - depending on how
   * important the sleep time is to you.
   */
}
mjaggard
quelle
4
Ist das ein Aufruf an Java?
Ken Sharp
14
Dies ist Java nicht Javascript
RousseauAlexandre
18
@RousseauAlexandre Falsch. Es ist JavaScript mit Rhino (zu der Zeit könnte es heutzutage auch Nashorn sein)
mjaggard
71

Wenn Sie jQuery verwenden, hat jemand tatsächlich ein "Delay" -Plugin erstellt, das nichts weiter als ein Wrapper für setTimeout ist:

// Delay Plugin for jQuery
// - http://www.evanbot.com
// - © 2008 Evan Byrne

jQuery.fn.delay = function(time,func){
    this.each(function(){
        setTimeout(func,time);
    });

    return this;
};

Sie können es dann wie erwartet in einer Reihe von Funktionsaufrufen verwenden:

$('#warning')
.addClass('highlight')
.delay(1000)
.removeClass('highlight');
Alan Plum
quelle
4
Das ist keine schlechte Lösung. Hält den Kontext und die Verkettbarkeit.
Nosredna
39
Ab jQuery 1.4 .delay()ist es Teil von jQuery (allerdings mit einer anderen Semantik als der obigen Implementierung). api.jquery.com/delay
Matt Ball
7
Was dieser Frage definitiv fehlte, war eine jQuery-Antwort . Ich bin so froh, dass wir es bekommen haben!
xDaizu
1
Wenn Sie eine Verzögerung zwischen zwei unabhängigen Anrufen benötigen, ja. Wenn Sie Verzögerungen benötigen, um eine Schleife zu verlangsamen, nein.
WGroleau
46

Ich habe auch nach Schlaflösung gesucht (nicht nach Produktionscode, nur nach Entwicklern / Tests) und diesen Artikel gefunden:

http://narayanraman.blogspot.com/2005/12/javascript-sleep-or-wait.html

... und hier ist ein weiterer Link zu clientseitigen Lösungen: http://www.devcheater.com/

Wenn Sie anrufen alert(), wird auch Ihr Code angehalten, während die Warnung angezeigt wird. Sie müssen einen Weg finden, um die Warnung nicht anzuzeigen, aber den gleichen Effekt zu erzielen. :) :)

a_w
quelle
35
Ich stimme zu, viele Leute sagen: "Nein, mach das nicht im Produktionscode!" Ja, ähm, ich will nicht. Ich möchte es in wegwerfbarem Testcode tun, und deshalb möchte ich nicht viel Zeit damit verbringen, eine elegante Lösung zu finden.
user435779
31

Hier ist eine einfache Lösung mit einem synchronen XMLHttpRequest:

function sleep(n){
  var request = new XMLHttpRequest();
  request.open('GET', '/sleep.php?n=' + n, false);  // `false` makes the request synchronous
  request.send(null);
}

Inhalt von sleep.php:

<?php sleep($_GET['n']);

Nennen Sie es jetzt mit: sleep (5);

pguardiario
quelle
5
@lukad, Verwenden Sie setTimeout()diese Option, wenn dies funktioniert. Wenn dies jedoch bedeutet, dass 1000 Rückrufzeilen aufgelöst werden, sieht dies möglicherweise nicht wie ein Witz aus.
Pguardiario
11
Einzigartiger Ansatz, obwohl leider nicht asynchrone XMLHttpRequests veraltet sind und in Zukunft entfernt werden. Was lustig ist, denn diese Tatsache hat mich überhaupt zu dieser Frage geführt.
Beejor
Dies ist eigentlich eine ziemlich gute Idee IMO. Obwohl ich nicht denke, dass die Schlaf-API (Request URL) öffentlich sein sollte, da sie missbraucht werden kann.
Vahid Amiri
@Beejor immer nur an die Zukunft zu denken bedeutet, von futuristischer Irrealität zu leben :-)
user1742529
Schön, aber wissen Sie, ob das Internet manchmal langsam ist oder die Ping-Zeit der Website hoch ist, als dass das Skript länger als die Argumentationszeit im Ruhezustand ist? Wenn Sie eine sleep(300)Website verwenden und die Antwort 150 ms dauert, wird der Javascript-Code 450 ms lang in den Ruhezustand versetzt. und wenn die Internetverbindung durch den Browser unterbrochen wird, funktioniert sie nur für 0 ms. Es ist also keine bessere Lösung
H Chauhan
30

Bitte schön. Wie der Code sagt, sei kein schlechter Entwickler und benutze dies auf Websites. Es ist eine Entwicklungsdienstprogrammfunktion.

// Basic sleep function based on ms.
// DO NOT USE ON PUBLIC FACING WEBSITES.
function sleep(ms) {
    var unixtime_ms = new Date().getTime();
    while(new Date().getTime() < unixtime_ms + ms) {}
}
Ian Maddox
quelle
17
Das ist im Grunde das Gleiche wie beim OP.
Andrew Barber
5
Genauer gesagt ist es das, was OP von einer ALTERNATIVE verlangt hat.
WGroleau
Die Lösung ist nicht gut, aber an einigen Stellen reagiert async/awaitsie leider nicht und wir müssen sie obligatorisch verwenden.
Nabi KAZ
21

Ich persönlich mag das einfache:

function sleep(seconds){
    var waitUntil = new Date().getTime() + seconds*1000;
    while(new Date().getTime() < waitUntil) true;
}

dann:

sleep(2); // Sleeps for 2 seconds

Ich benutze es die ganze Zeit, um falsche Ladezeiten zu erstellen, während ich Skripte in P5js erstelle

melMass
quelle
3
Ich sehe dies als die am besten optimierte Version der Hauptfrage: Es werden keine Berechnungen innerhalb der Schleife durchgeführt, sondern nur ein einfacher Vergleich. Es ist ein bisschen schwer zu lesen.
Hegez
4
TUN SIE DAS NIEMALS. Haben Sie die CPU-Auslastung überprüft, während diese Funktion funktioniert? Es sollte nahe bei 100% liegen, wenn Sie genügend Zeit dafür geben.
Noego
2
@hegez: Angesichts der Tatsache, dass die Schleife für eine festgelegte Wanduhrzeit ausgeführt wird, scheint es, als sei die Optimierung der Schleife eher nebensächlich.
ShadowRanger
@noego Wie so? Ich habe gerade in Knoten 10 getestet, ich habe überhaupt keine Änderung der CPU-Auslastung
melMass
@melMass Diese Funktion blockiert den Knoten-Thread nur für n Sekunden, indem die CPU zu 100% ausgelastet bleibt. Diese "Lösung" ist aus diesen beiden Gründen (Blockieren + CPU-Killer) eine äußerst schlechte Idee. Das Warten muss nicht blockiert sein, daher asynchron.
Jeremy Thille
20

Zuerst:

Definieren Sie eine Funktion, die Sie wie folgt ausführen möchten:

function alertWorld(){
  alert("Hello World");
}

Planen Sie dann die Ausführung mit der setTimeout-Methode:

setTimeout(alertWorld,1000)

Beachten Sie zwei Dinge

  • Das zweite Argument ist die Zeit in Millisekunden
  • Als erstes Argument müssen Sie nur den Namen (die Referenz) der Funktion ohne die Klammer übergeben
Pablo Fernandez
quelle
19

  await new Promise(resolve => setTimeout(resolve, 2000));

Stellen Sie sicher, dass Ihre aufrufende Funktion asynchron ist

verifiziert und funktioniert gut

Ahmed Mohammedali
quelle
1
Schließlich. Die einzige Antwort.
Jeremy Thille
18

Eine bessere Lösung, um die Dinge so aussehen zu lassen, wie es die meisten Menschen wollen, ist die Verwendung einer anonymen Funktion:

alert('start');
var a = 'foo';
//lots of code
setTimeout(function(){  //Beginning of code that should run AFTER the timeout
    alert(a);
    //lots more code
},5000);  // put the timeout here

Dies ist wahrscheinlich der nächste Schritt zu etwas, das einfach das tut, was Sie wollen.

Hinweis: Wenn Sie mehrere Schlafplätze benötigen, kann dies in Eile hässlich werden und Sie müssen möglicherweise Ihr Design überdenken.

Mainguy
quelle
Dies ist die, die für mich auf Desktop-Browsern und einem älteren Mobiltelefon funktioniert hat. Die anderen, die ich ausprobiert habe, haben nicht bei allen funktioniert.
Mike
10

Für Browser stimme ich zu, dass setTimeout und setInterval der richtige Weg sind.

Für serverseitigen Code ist möglicherweise eine Blockierungsfunktion erforderlich (z. B. um eine effektive Thread-Synchronisierung durchzuführen).

Wenn Sie node.js und meteor verwenden, sind Sie möglicherweise auf die Einschränkungen bei der Verwendung von setTimeout in einer Glasfaser gestoßen. Hier ist der Code für den serverseitigen Ruhezustand.

var Fiber = require('fibers');

function sleep(ms) {
    var fiber = Fiber.current;
    setTimeout(function() {
        fiber.run();
    }, ms);
    Fiber.yield();
}

Fiber(function() {
    console.log('wait... ' + new Date);
    sleep(1000);
    console.log('ok... ' + new Date);
}).run();
console.log('back in main');

Siehe: https://github.com/laverdet/node-fibers#sleep

Homer6
quelle
Server may require a blocking function... Ich verstehe nicht, wie stark es ist, den einzigen Thread von Node zu blockieren und Ihren gesamten Server für einige Sekunden nicht mehr zu reagieren, aber was auch immer
Jeremy Thille
10

Ich würde setTimeOut in ein Versprechen für Codekonsistenz mit anderen asynchronen Aufgaben einkapseln: Demo in Fiddle

function sleep(ms)
{
    return(new Promise(function(resolve, reject) {        
        setTimeout(function() { resolve(); }, ms);        
    }));    
}

So verwendet:

sleep(2000).then(function() { 
   // Do something
});

Es ist leicht, sich die Syntax zu merken, wenn Sie Promises verwendet haben.

Elo
quelle
4
Warum ist das besser als nur setTimeout (function () {/ * etwas tun * /}, 2000)?
JSideris
10

2019 Update mit Atomics.wait

Sollte in Knoten 9.3 oder höher funktionieren.

Ich brauchte einen ziemlich genauen Timer in Node.js und es funktioniert großartig dafür. Es scheint jedoch, dass die Unterstützung in Browsern äußerst begrenzt ist.

let ms = 10000;
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);

Lief ein paar 10-Sekunden-Timer-Benchmarks.

Mit setTimeout erhalte ich einen Fehler von bis zu 7000 Mikrosekunden. (7 ms)

Mit Atomics scheint mein Fehler unter 600 Mikrosekunden zu bleiben. (0,6 ms)

Update 2020: Zusammenfassend

function sleep(millis){ // need help of a server-side page
  let netMillis=Math.max(millis-5,0); //assuming 5ms overhead
  let xhr=new XMLHttpRequest();
  xhr.open('GET','/sleep.jsp?millis='+netMillis+'&rand='+Math.random(), false);
  try{
    xhr.send();
  }catch(e){
  }
}
function sleepAsync(millis){ // use only in async function
  let netMillis=Math.max(millis-1,0); // assuming 1ms overhead
  return new Promise((resolve)=>{
    setTimeout(resolve, netMillis);
  });
}
function sleepSync(millis){ // use only in worker thread, currently Chrome-only
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, millis);
}

function sleepTest(){
  console.time('sleep');
  sleep(1000);
  console.timeEnd('sleep');
}
async function sleepAsyncTest(){
  console.time('sleepAsync');
  await sleepAsync(1000);
  console.timeEnd('sleepAsync');
}
function sleepSyncTest(){ 
  let source=`${sleepSync.toString()}
    console.time('sleepSync');
    sleepSync(1000);
    console.timeEnd('sleepSync');`;
  let src='data:text/javascript,'+encodeURIComponent(source);
  console.log(src);
  var worker=new Worker(src);
}

davon sleep.jspsieht die serverseitige Seite zB aus

<%
try{
  Thread.sleep(Long.parseLong(request.getParameter("millis")));
}catch(InterruptedException e){}
%>
Fuweichin
quelle
Meiner Meinung nach besser als die akzeptierte Lösung, die ohne async / await im Aufrufer nicht als einfache Funktion implementiert werden kann.
GroovyDotCom
Ja, solange Sie wissen, dass dies blockiert und das normalerweise keine gute Sache ist
Kapytanhook
Ziemlich cool, aber die Tatsache, dass dies nur in Chrome und Firefox wirklich unterstützt wird, macht es für die Verwendung im Web nicht sehr brauchbar. (November 2019)
JGreatorex
9

Die meisten Antworten hier sind falsch oder zumindest veraltet. Es gibt keinen Grund, warum Javascript Single-Threaded sein muss, und das ist es auch nicht. Heute unterstützen alle gängigen Browser Worker, bevor dies der Fall war, unterstützten andere Javascript-Laufzeiten wie Rhino und Node.js Multithreading.

'Javascript is single threaded' ist keine gültige Antwort. Wenn Sie beispielsweise eine Sleep-Funktion in einem Worker ausführen, wird der im UI-Thread ausgeführte Code nicht blockiert.

In neueren Laufzeiten, die Generatoren und Ertrag unterstützen, könnte man der Sleep-Funktion in einer Umgebung mit einem Thread ähnliche Funktionen hinzufügen:

// This is based on the latest ES6 drafts.
// js 1.7+ (SpiderMonkey/Firefox 2+) syntax is slightly different

// run code you want to sleep here (ommit star if using js 1.7)
function* main(){
    for (var i = 0; i < 10; i++) {
        // to sleep for 10 milliseconds 10 times in a row
        yield 10;
    }

    yield 5;
    console.log('I just slept 5 milliseconds!');
}

// resume the given generator after ms milliseconds
function resume(ms, generator){
    setTimeout(function(){
        // ommit .value if using js 1.7
        var nextSleep = generator.next().value;
        resume(nextSleep, generator);
    }, ms);
}

// initialize generator and get first sleep for recursive function
var
    generator = main(),
    firstSleep = generator.next().value;

// initialize recursive resume function
resume(firstSleep, generator);

Diese Nachahmung des Schlafes unterscheidet sich von einer echten Schlaffunktion, da sie den Thread nicht blockiert. Es ist einfach Zucker zusätzlich zu der aktuellen setTimeout-Funktion von Javascript. Dieser Funktionstyp wurde in Task.js implementiert und sollte heute in Firefox funktionieren.

Gabriel Ratener
quelle
Worker sind zumindest bis Version 10 nicht im IE implementiert. Dies repräsentiert derzeit eine große Anzahl von Benutzern.
Beejor
Richtig, und selbst dann ist es nicht praktikabel, sleepmit mehreren Workern zu implementieren . Bei Verwendung von Node.js sind Generatorfunktionen bereits implementiert und können wie beschrieben verwendet werden. Mainstream-Browser haben bis heute nicht alle Generatoren implementiert.
Gabriel Ratener
8

Ich habe einige Webseiten über Javascript Sleep / Wait durchsucht / gegoogelt ... und es gibt KEINE Antwort, wenn Sie möchten, dass Javascript "RUN, DELAY, RUN" ist ... was die meisten Leute auch bekamen, war "RUN, RUN" (nutzlos) Zeug), RUN "oder" RUN, RUN + verzögert RUN "....

Also habe ich ein paar Burger gegessen und mir Gedanken gemacht ::: Hier ist eine Lösung, die funktioniert ... aber du musst deine laufenden Codes zerhacken ... ::: Ja, ich weiß, das ist nur ein einfacher zu lesendes Refactoring. . immer noch...

//......................................... //Beispiel 1:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
//javascript sleep by "therealdealsince1982"; copyrighted 2009
//setInterval
var i = 0;

function run() {
    //pieces of codes to run
    if (i==0){document.getElementById("id1").innerHTML= "<p>code segment "+ i +" is ran</p>"; }
    if (i==1){document.getElementById("id1").innerHTML= "<p>code segment "+ i +" is ran</p>"; }
    if (i==2){document.getElementById("id1").innerHTML= "<p>code segment "+ i +" is ran</p>"; }
    if (i >2){document.getElementById("id1").innerHTML= "<p>code segment "+ i +" is ran</p>"; }
    if (i==5){document.getElementById("id1").innerHTML= "<p>all code segment finished running</p>"; clearInterval(t); } //end interval, stops run
    i++; //segment of code finished running, next...
}

run();
t=setInterval("run()",1000);

</script>
</body>
</html>

// .................................... // Beispiel2:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
//javascript sleep by "therealdealsince1982"; copyrighted 2009
//setTimeout
var i = 0;

function run() {
    //pieces of codes to run, can use switch statement
    if (i==0){document.getElementById("id1").innerHTML= "<p>code segment "+ i +" ran</p>"; sleep(1000);}
    if (i==1){document.getElementById("id1").innerHTML= "<p>code segment "+ i +" ran</p>"; sleep(2000);}
    if (i==2){document.getElementById("id1").innerHTML= "<p>code segment "+ i +" ran</p>"; sleep(3000);}
    if (i==3){document.getElementById("id1").innerHTML= "<p>code segment "+ i +" ran</p>";} //stops automatically
    i++;
}

function sleep(dur) {t=setTimeout("run()",dur);} //starts flow control again after dur

run(); //starts
</script>
</body>
</html>

// ................. Beispiel3:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
//javascript sleep by "therealdealsince1982"; copyrighted 2009
//setTimeout
var i = 0;

function flow() {
    run(i);
    i++; //code segment finished running, increment i; can put elsewhere
    sleep(1000);
    if (i==5) {clearTimeout(t);} //stops flow, must be after sleep()
}

function run(segment) {
    //pieces of codes to run, can use switch statement
    if (segment==0){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
    if (segment==1){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
    if (segment==2){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
    if (segment >2){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
}

function sleep(dur) {t=setTimeout("flow()",dur);} //starts flow control again after dur

flow(); //starts flow
</script>
</body>
</html>

// .............. Beispiel4:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
//javascript sleep by "therealdealsince1982"; copyrighted 2009
//setTimeout, switch
var i = 0;

function flow() {
    switch(i)
    {
        case 0:
            run(i);
            sleep(1000);
            break;
        case 1:
            run(i);
            sleep(2000);
            break;
        case 5:
            run(i);
            clearTimeout(t); //stops flow
            break;
        default:
            run(i);
            sleep(3000);
            break;
    }
}

function run(segment) {
    //pieces of codes to run, can use switch statement
    if (segment==0){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
    if (segment==1){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
    if (segment==2){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
    if (segment >2){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
    i++; //current segment of code finished running, next...
}

function sleep(dur) {t=setTimeout("flow()",dur);} //starts flow control again after dur

flow(); //starts flow control for first time...
</script>
</body>
</html>
user207408
quelle
5
Ok, das funktioniert mit setTimeput, aber es ist schwer zu sehen, was passiert. Die Verwendung von setTimeout selbst ist einfacher.
Naugtur
7
function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if ((new Date().getTime() - start) > milliseconds){
      break;
    }
  }
}
Shemeer M Ali
quelle
Es ist das gleiche wie die eigentliche Frage. Es macht nicht viel Sinn, es zur richtigen Antwort zu machen.
EML
2
Keine gute Lösung - wenn Sie dies in Seleniums JavaScriptExecutor verwenden, hängt mein Chrome-Browser in etwa 50% der Fälle auf einem 2104 MacBook Pro.
Schmirgel
7

Die kürzeste Lösung ohne Abhängigkeiten:

await new Promise(resolve => setTimeout(resolve, 5000));
k06a
quelle
In IE11 funktioniert es nicht. Wir erhalten einen Syntaxfehler für die Pfeilfunktion.
DDphp
@ Java-DK verwendenawait new Promise(function(resolve) { setTimeout(resolve, 5000); });
k06a
6

In JavaScript kann man so nicht schlafen, oder eher nicht. Wenn Sie eine Schlaf- oder eine while-Schleife ausführen, bleibt der Browser des Benutzers hängen, bis die Schleife abgeschlossen ist.

Verwenden Sie einen Timer, wie in dem Link angegeben, auf den Sie verwiesen haben.

Andrew Dunkman
quelle
6

Ein Szenario, in dem Sie möglicherweise eine sleep () - Funktion anstelle von setTimeout () wünschen, besteht darin, dass Sie eine Funktion haben, die auf einen Benutzerklick reagiert und letztendlich ein neues Popup-Fenster öffnet, und dass Sie eine Verarbeitung eingeleitet haben, die einen kurzen Zeitraum erfordert zu vervollständigen, bevor das Popup angezeigt wird. Wenn Sie das geöffnete Fenster in einen geschlossenen Zustand verschieben, wird es normalerweise vom Browser blockiert.

Acuth
quelle
6

Ich kann den Zweck einer Schlaffunktion verstehen, wenn Sie sich mit synchroner Ausführung befassen müssen. Die Funktionen setInterval und setTimeout erstellen einen parallelen Ausführungsthread, der die Ausführungssequenz an das Hauptprogramm zurückgibt. Dies ist unwirksam, wenn Sie auf ein bestimmtes Ergebnis warten müssen. Natürlich kann man Ereignisse und Handler verwenden, aber in einigen Fällen ist dies nicht beabsichtigt.

Naazgull
quelle
6

Meine zwei Bits hinzufügen. Ich musste zu Testzwecken warten. Ich wollte den Code nicht aufteilen, da dies eine Menge Arbeit bedeuten würde.

for (var i=0;i<1000000;i++){                    
     //waiting
  }

Ich sehe keinen Nachteil darin und es hat den Trick für mich getan.

caiocpricci2
quelle
Das könnte weg kompiliert werden.
Viktor Sehr
Bitte mach es nicht so. Dies ist ein blockierender Schlafaufruf, was bedeutet, dass kein anderes Javascript ausgeführt werden kann, während Ihr Code den JS-Thread belastet.
Steve Midgley
5
@SteveMidgley "kein anderes Javascript [kann] ausgeführt werden, während Ihr Code den JS-Thread belastet" scheint mir genau das zu sein, was das OP tun möchte ¯_ (ツ) _ / ¯
drigoangelo
1
Ich habe gerade einige Tests durchgeführt und es scheint, dass sogar eine leere Schleife den Browser und die CPU blockiert (nicht nur JavaScript). Die Verwendung von forSchleifen wird fast immer sofort ausgeführt, unabhängig vom Maximalwert für iund sogar mit komplexem mathematischem Code. Wenn Sie also nicht nur ein paar Millisekunden warten, scheint es in JS immer noch keine Möglichkeit zu geben, elegant zu schlafen.
Beejor
1 Million ist zu groß. Für mich genug 10k
Vlad
6

Dies kann mit der Schlafmethode von Java erfolgen. Ich habe es in FF und IE getestet und es sperrt den Computer nicht, zerkaut keine Ressourcen und verursacht keine endlosen Server-Treffer. Scheint mir eine saubere Lösung zu sein.

Zuerst müssen Sie Java auf die Seite laden und seine Methoden verfügbar machen. Um das zu tun, habe ich Folgendes getan:

<html>
<head>

<script type="text/javascript">

  function load() {
    var appletRef = document.getElementById("app");
    window.java = appletRef.Packages.java;
  } // endfunction

</script>

<body onLoad="load()">

<embed id="app" code="java.applet.Applet" type="application/x-java-applet" MAYSCRIPT="true" width="0" height="0" />

Dann müssen Sie nur noch Folgendes tun, wenn Sie eine schmerzlose Pause in Ihrem JS wünschen:

java.lang.Thread.sleep(xxx)

Wobei xxx die Zeit in Millisekunden ist. In meinem Fall (zur Rechtfertigung) war dies Teil der Erfüllung von Back-End-Bestellungen in einem sehr kleinen Unternehmen, und ich musste eine Rechnung drucken, die vom Server geladen werden musste. Dazu habe ich die Rechnung (als Webseite) in einen iFrame geladen und dann den iFrame gedruckt. Natürlich musste ich warten, bis die Seite vollständig geladen war, bevor ich drucken konnte, also musste der JS pausieren. Dies wurde erreicht, indem die Rechnungsseite (im iFrame) mit dem Ereignis onLoad ein ausgeblendetes Formularfeld auf der übergeordneten Seite änderte. Und der Code auf der übergeordneten Seite zum Drucken der Rechnung sah folgendermaßen aus (irrelevante Teile aus Gründen der Übersichtlichkeit):

var isReady = eval('document.batchForm.ready');
isReady.value=0;

frames['rpc_frame'].location.href=url;

while (isReady.value==0) {
  java.lang.Thread.sleep(250);
} // endwhile

window.frames['rpc_frame'].focus();
window.frames['rpc_frame'].print();

Der Benutzer drückt also die Taste, das Skript lädt die Rechnungsseite, wartet, überprüft jede Viertelsekunde, ob die Rechnungsseite vollständig geladen ist, und öffnet dann den Druckdialog, damit der Benutzer sie an den Drucker senden kann. QED.

Rachael
quelle
12
Scheint ziemlich monströs zu sein, wenn man bedenkt, was der Autor einfach erreichen wollte.
Xaralis
2
Dies hängt von veralteten Java-Applets ab.
Vahid Amiri
6

Viele der Antworten beantworten die Frage nicht (direkt) und diese auch nicht ...

Hier sind meine zwei Cent (oder Funktionen):

Wenn Sie weniger klobige Funktionen als setTimeoutund möchten setInterval, können Sie sie in Funktionen einschließen, die nur die Reihenfolge der Argumente umkehren und ihnen nette Namen geben:

function after(ms, fn){ setTimeout(fn, ms); }
function every(ms, fn){ setInterval(fn, ms); }

CoffeeScript-Versionen:

after = (ms, fn)-> setTimeout fn, ms
every = (ms, fn)-> setInterval fn, ms

Sie können sie dann mit anonymen Funktionen gut verwenden:

after(1000, function(){
    console.log("it's been a second");
    after(1000, function(){
        console.log("it's been another second");
    });
});

Jetzt liest es sich leicht als "nach N Millisekunden, ..." (oder "alle N Millisekunden, ...")

1j01
quelle
5

Für den speziellen Fall, dass eine Reihe von Aufrufen, die von einer Schleife ausgeführt werden, entfernt werden sollen, können Sie mit dem Prototyp den folgenden Code verwenden. Ohne Prototyp können Sie die Verzögerungsfunktion durch setTimeout ersetzen.

function itemHandler(item)
{
    alert(item);
}

var itemSet = ['a','b','c'];

// Each call to itemHandler will execute
// 1 second apart
for(var i=0; i<itemSet.length; i++)
{
    var secondsUntilExecution = i;
    itemHandler.delay(secondsUntilExecution, item)
}
Beauburrier
quelle
5

Wenn Sie sich auf node.js befinden, können Sie sich die Fasern ansehen - eine native C-Erweiterung für Node, eine Art Multithreading-Simulation.

Es ermöglicht Ihnen, eine echte zu tun sleep auf eine Weise zu erstellen, die die Ausführung in einer Faser blockiert, aber im Hauptfaden und anderen Fasern nicht blockiert.

Hier ist ein Beispiel, das frisch aus ihrer eigenen Readme stammt:

// sleep.js

var Fiber = require('fibers');

function sleep(ms) {
    var fiber = Fiber.current;
    setTimeout(function() {
        fiber.run();
    }, ms);
    Fiber.yield();
}

Fiber(function() {
    console.log('wait... ' + new Date);
    sleep(1000);
    console.log('ok... ' + new Date);
}).run();
console.log('back in main');

- und die Ergebnisse sind:

$ node sleep.js
wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
back in main
ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
Tomekwi
quelle