Wat is de JavaScript-versie van sleep()?

Is er een betere manier om een ​​sleep in JavaScript te engineeren dan de volgende pausecomp-functie (van hier overgenomen)?

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

Dit is geen duplicaat van Slaap in JavaScript – vertraging tussen acties ; Ik wil een echte slaap in het midden van een functie, en geen vertraging voordat een stukje code wordt uitgevoerd.


Antwoord 1, autoriteit 100%

2017 2021-update

Sinds 2009 toen deze vraag werd gesteld, is JavaScript aanzienlijk geëvolueerd. Alle andere antwoorden zijn nu achterhaald of te ingewikkeld. Dit is de huidige 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();

Antwoord 2, autoriteit 24%

(Zie het bijgewerkte antwoord voor 2016)

Ik denk dat het volkomen redelijk is om een ​​actie uit te voeren, te wachten en dan nog een actie uit te voeren. Als je gewend bent om in talen met meerdere threads te schrijven, heb je waarschijnlijk het idee om uitvoering te geven voor een bepaalde tijd totdat je thread wakker wordt.

Het probleem hier is dat JavaScript een op gebeurtenissen gebaseerd model met één thread is. Hoewel het in een specifiek geval leuk kan zijn om de hele motor een paar seconden te laten wachten, is het over het algemeen een slechte gewoonte. Stel dat ik uw functies wilde gebruiken terwijl ik die van mezelf schreef? Toen ik je methode aanriep, liepen al mijn methoden vast. Als JavaScript op de een of andere manier de uitvoeringscontext van uw functie zou kunnen behouden, ergens zou kunnen opslaan, het dan terug zou kunnen brengen en later zou kunnen doorgaan, dan zou slaap kunnen plaatsvinden, maar dat zou in feite threading zijn.

Je zit dus vrijwel vast aan wat anderen hebben gesuggereerd — je moet je code opsplitsen in meerdere functies.

Je vraag is dan ook een beetje een verkeerde keuze. Er is geen manier om te slapen zoals je wilt, en je moet ook niet de oplossing nastreven die je voorstelt.


Antwoord 3, autoriteit 19%

In JavaScript herschrijf ik elke functie zodat deze zo snel mogelijk kan eindigen. U wilt dat de browser weer de controle heeft, zodat deze uw DOM-wijzigingen kan doorvoeren.

Elke keer dat ik midden in mijn functie wilde slapen, heb ik een refactoring doorgevoerd om een ​​setTimeout() te gebruiken.

Bewerken

De beruchte slaap- of vertragingsfunctie in elke taal is veelbesproken. Sommigen zullen zeggen dat er altijd een signaal of terugroepactie moet zijn om een ​​bepaalde functionaliteit te activeren, anderen zullen beweren dat een willekeurig moment van vertraging soms nuttig is. Ik zeg dat ieder zijn eigen en één regel kan nooit iets dicteren in deze branche.

Het schrijven van een slaapfunctie is eenvoudig en wordt nog bruikbaarder met JavaScript Promises:

// sleep time expects milliseconds
function sleep (time) {
  return new Promise((resolve) => setTimeout(resolve, time));
}
// Usage!
sleep(500).then(() => {
    // Do something after the sleep!
});

Antwoord 4, autoriteit 9%

In Firebug (en waarschijnlijk andere JavaScript-consoles), gebeurt er niets na druk op enter, alleen na de opgegeven slaapduur (…)

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

Voorbeeld van gebruik:

function sleepFor(sleepDuration){
    var now = new Date().getTime();
    while(new Date().getTime() < now + sleepDuration){ 
        /* Do nothing */ 
    }
}
function sleepThenAct(){
    sleepFor(2000);
    console.log("Hello, JavaScript sleep!");
}
sleepThenAct()

Antwoord 5, autoriteit 5%

Ik ben het eens met de andere posters. Een drukke slaap is gewoon een slecht idee.

setTimeout houdt de uitvoering echter niet tegen. Het voert de volgende regel van de functie uit onmiddellijk nadat de time-out is SET, niet nadat de time-out is verstreken, dus dat volbrengt niet dezelfde taak die een slaapstand zou volbrengen.

De manier om dit te doen is om je functie op te splitsen in voor- en nadelen.

function doStuff()
{
  // Do some things
  setTimeout(continueExecution, 10000) // Wait ten seconds before continuing
}
function continueExecution()
{
   // Finish doing things after the pause
}

Zorg ervoor dat uw functienamen nog steeds nauwkeurig beschrijven wat elk onderdeel doet (d.w.z. GatherInputThenWait en CheckInput, in plaats van funcPart1 en funcPart2)

Met deze methode wordt het doel bereikt om de regels code die u beslist pas na uw time-out uit te voeren, terwijl u toch de controle teruggeeft aan de client-pc om al het andere dat in de wachtrij staat uit te voeren.

>

Zoals aangegeven in de opmerkingen zal dit absoluut niet werken in een lus. Je zou wat fancy (lelijk) hacken kunnen doen om het in een lus te laten werken, maar over het algemeen levert dat alleen maar rampzalige spaghetti-code op.


Antwoord 6, autoriteit 4%

Voor de liefde van $DEITY, maak alsjeblieft geen druk-wacht-slaapfunctie. setTimeout en setInterval doen alles wat je nodig hebt.

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

Antwoord 7, autoriteit 3%

Als je (zoals ik) JavaScript gebruikt met Rhino, je kunt gebruiken…

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.
   */
}

Antwoord 8, autoriteit 2%

Als je jQuery gebruikt, heeft iemand een “delay”-plug-in gemaakt die niets meer is dan een wrapper voor setTimeout:

// 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;
};

Je kunt het dan gewoon gebruiken in een rij functieaanroepen zoals verwacht:

$('#warning')
.addClass('highlight')
.delay(1000)
.removeClass('highlight');

Antwoord 9

Ik heb ook naar een slaapoplossing gezocht (niet voor productiecode, alleen voor ontwikkeling en tests) en vond dit artikel:

JavaScript sleep() of wacht()

…en hier is nog een artikel met oplossingen aan de clientzijde: JavaScript-slaapstand

Als je alert() aanroept, wordt je code ook gepauzeerd, terwijl de waarschuwing wordt weergegeven — je moet een manier vinden om geen waarschuwing weer te geven, maar hetzelfde effect te krijgen . 🙂


Antwoord 10

Gebruik:

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

Antwoord 11

Hier ga je. Zoals de code zegt, wees geen slechte ontwikkelaar en gebruik dit op websites. Het is een hulpprogramma voor ontwikkeling.

// 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) {}
}

Antwoord 12

Hier is een eenvoudige oplossing met een synchrone XMLHttpRequest:

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

Inhoud van bestand sleep.php:

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

Noem het nu met:

sleep(5);

Antwoord 13

Eerst:

Definieer een functie die u als volgt wilt uitvoeren:

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

Plan vervolgens de uitvoering ervan met de setTimeout methode:

setTimeout(alertWorld, 1000)

Let op twee dingen

  • het tweede argument is tijd in milliseconden
  • als eerste argument moet je alleen de naam (referentie) van de functie doorgeven, zonder de haakjes

Antwoord 14

Persoonlijk houd ik van het simpele:

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

dan:

sleep(2); // Sleeps for 2 seconds

Ik gebruik het de hele tijd om valse laadtijden te creëren terwijl ik scripts maak in p5.js.


Antwoord 15

Een betere oplossing om dingen eruit te laten zien zoals de meeste mensen willen, is door een anonieme functie te gebruiken:

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

Dit komt waarschijnlijk het dichtst in de buurt van iets dat gewoon doet wat je wilt.

Let op, als je meerdere slaapplaatsen nodig hebt, kan dit snel lelijk worden en moet je misschien je ontwerp heroverwegen.


Antwoord 16

2019 Update met Atomics .wacht

Het zou moeten werken in Node.js 9.3 of hoger.

Ik had een behoorlijk nauwkeurige timer nodig in Node.js en daar werkt het prima voor.

Het lijkt er echter op dat er extreem beperkte ondersteuning is in browsers.

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

Antwoord 17

De kortste oplossing zonder enige afhankelijkheden:

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

Antwoord 18

De meeste antwoorden hier zijn misleidend of op zijn minst verouderd. Er is geen reden waarom JavaScript single-threaded moet zijn, en dat is het ook niet. Tegenwoordig ondersteunen alle reguliere browsers werknemers. Voordat dit het geval was, werden andere JavaScript-runtimes zoals Rhino en Node.js ondersteund multithreading.

‘JavaScript is single threaded’ is geen geldig antwoord. Het uitvoeren van een slaapfunctie binnen een werknemer zou bijvoorbeeld geen enkele code blokkeren die in de UI-thread wordt uitgevoerd.

In nieuwere runtimes die generatoren en opbrengst ondersteunen, zou men vergelijkbare functionaliteit kunnen toevoegen aan de slaapfunctie in een omgeving met één thread:

// This is based on the latest ES6 drafts.
// JavaScript 1.7+ (SpiderMonkey/Firefox 2+) syntax is slightly different
// Run code you want to sleep here (omit star if using JavaScript 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(){
        // Omit .value if using JavaScript 1.7
        var nextSleep = generator.next().value;
        resume(nextSleep, generator);
    }, ms);
}
// Initialize a generator and get first sleep for the recursive function
var
    generator = main(),
    firstSleep = generator.next().value;
// Initialize recursive resume function
resume(firstSleep, generator);

Deze imitatie van slaap is anders dan een echte slaapfunctie omdat het de draad niet blokkeert. Het is gewoon een aanvulling op de huidige setTimeout-functie van JavaScript. Dit type functionaliteit is geïmplementeerd in Task.js en zou vandaag in Firefox moeten werken.


Antwoord 19

Voor browsers ga ik ermee akkoord dat setTimeout en setInterval de juiste keuze zijn.

Maar voor code aan de serverzijde kan het een blokkeerfunctie vereisen (bijvoorbeeld, zodat u effectief threadsynchronisatie kunt hebben).

Als je Node.js en Meteor, bent u mogelijk tegen de beperkingen aangelopen van het gebruik van setTimeout in een fiber. Hier is de code voor server-side slaap.

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

Zie: Node.js-vezels, slaap


Antwoord 20

Ik zou setTimeOut in een belofte inkapselen voor codeconsistentie met andere asynchrone taken: demo in Fiddle

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

Het wordt als volgt gebruikt:

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

Het is gemakkelijk om de syntaxis te onthouden als je gewend bent om Promises te gebruiken.


Antwoord 21

Ik heb nogal wat webpagina’s doorzocht/gegoogled op JavaScript sleep/wait… en er is geen antwoord als je wilt dat JavaScript "RUN, DELAY, RUN"… wat het meest mensen kregen was ofwel, "RUN, RUN(nutteloos spul), RUN" of “RUN, RUN + vertraagde RUN”…

Ik dacht:
hier is een oplossing die werkt … maar je moet je lopende codes hakken …:
Ja, ik weet het, dit is gewoon een gemakkelijker te lezen refactoring… toch…

Voorbeeld 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>

Voorbeeld 2:

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

Voorbeeld 3:

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

Voorbeeld 4:

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

Antwoord 22

Ik begrijp het doel van een slaapfunctie als je te maken hebt met synchrone uitvoering. De functies setInterval en setTimeout creëren een parallelle uitvoeringsthread die de uitvoeringsvolgorde terugstuurt naar het hoofdprogramma, wat niet effectief is als u op een bepaald resultaat moet wachten. Natuurlijk kan men gebeurtenissen en handlers gebruiken, maar in sommige gevallen is dit niet de bedoeling.


Antwoord 23

function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if ((new Date().getTime() - start) > milliseconds){
      break;
    }
  }
}

Antwoord 24

Als je minder onhandige functies wilt dan setTimeout en setInterval, kun je ze in functies plaatsen die de volgorde van de argumenten gewoon omkeren en ze mooie namen geven:

p>

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

CoffeeScript-versies:

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

Je kunt ze dan mooi gebruiken met anonieme functies:

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

Nu leest het gemakkelijk als "na N milliseconden, …" (of "elke N milliseconden, …")


Antwoord 25

Je kunt zo’n slaap niet doen in JavaScript, of beter gezegd, dat zou je ook niet moeten doen. Als u een sleep- of while-lus uitvoert, blijft de browser van de gebruiker hangen totdat de lus is voltooid.

Gebruik een timer, zoals gespecificeerd in de link waarnaar je verwijst.


Antwoord 26

Een scenario waarin u wellicht een sleep()-functie wilt gebruiken in plaats van setTimeout() te gebruiken, is als u een functie hebt die reageert op een gebruikersklik die uiteindelijk een nieuw pop-upvenster opent en u een verwerking hebt gestart die vereist is een korte periode voordat de pop-up wordt weergegeven. Als u het geopende venster naar een sluiting verplaatst, betekent dit dat het meestal wordt geblokkeerd door de browser.


Antwoord 27

Het kan worden gedaan met behulp van de slaapmethode van Java. Ik heb het getest in Firefox en Internet-Explorer en het vergrendelt de computer niet, vreet bronnen op en veroorzaakt geen eindeloze serverhits. Het lijkt me een schone oplossing.

Eerst moet u Java op de pagina laden en de methoden beschikbaar maken. Om dat te doen, deed ik dit:

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

Het enige wat u hoeft te doen als u een pijnloze pauze in uw JavaScript-code wilt, is:

java.lang.Thread.sleep(xxx)

Waarbij xxx tijd is in milliseconden. In mijn geval (ter rechtvaardiging) was dit onderdeel van de back-end orderafhandeling bij een heel klein bedrijf en moest ik een factuur afdrukken die van de server moest worden geladen. Ik deed het door de factuur (als webpagina) in een iFrame te laden en vervolgens het iFrame af te drukken.

Natuurlijk moest ik wachten tot de pagina volledig was geladen voordat ik kon afdrukken, dus de JavaScript-code moest worden onderbroken. Ik heb dit bereikt door de factuurpagina (in het iFrame) een verborgen formulierveld op de bovenliggende pagina te laten wijzigen met de onLoad-gebeurtenis. En de code op de bovenliggende pagina om de factuur af te drukken zag er als volgt uit (irrelevante delen geknipt voor de duidelijkheid):

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

Dus de gebruiker drukt op de knop, het script laadt de factuurpagina, wacht, controleert elk kwartaal of de factuurpagina klaar is met laden, en opent het afdrukvenster zodat de gebruiker deze naar de printer kan sturen. QED.


Antwoord 28

Als u zich op Node.js bevindt, kunt u een kijkje nemen op vezels een native C-extensie voor node, een soort multi-threading-simulatie.

Het stelt je in staat om een ​​echte sleep te doen op een manier die de uitvoering in een vezel blokkeert, maar het is niet-blokkerend in de hoofdthread en andere vezels.

Hier is een voorbeeld vers uit hun eigen leesmij:

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

en de resultaten zijn:

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

Antwoord 29

Sinds Node.js 7.6 kunt u combineer de functie promisify uit de module utils met setTimeout.

const sleep = require('util').promisify(setTimeout)

Algemeen gebruik

async function main() {
    console.time("Slept for")
    await sleep(3000)
    console.timeEnd("Slept for")
}
main()

Vraaggebruik

async function asyncGenerator() {
    while (goOn) {
      var fileList = await listFiles(nextPageToken);
      await sleep(3000)
      var parents = await requestParents(fileList);
    }
  }

Antwoord 30

Voor het specifieke geval dat u een reeks aanroepen die door een lus worden uitgevoerd, wilt spacen, kunt u zoiets als de onderstaande code met prototype gebruiken. Zonder prototype kunt u de vertragingsfunctie vervangen door setTimeout.

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

LEAVE A REPLY

Please enter your comment!
Please enter your name here

1 + 15 =

Other episodes