Qual è la versione JavaScript di sleep ()?



14 Answers

(Vedi la risposta aggiornata per il 2016 )

Penso che sia perfettamente ragionevole voler eseguire un'azione, attendere, quindi eseguire un'altra azione. Se sei abituato a scrivere in lingue multi-thread, probabilmente hai l'idea di dare esecuzione per un certo periodo di tempo fino a quando il thread non si attiva.

Il problema qui è che JavaScript è un modello basato su eventi a thread singolo. Mentre in un caso specifico, potrebbe essere bello avere l'intero motore in attesa per qualche secondo, in generale è una cattiva pratica. Supponiamo che volessi usare le tue funzioni mentre scrivevo la mia? Quando ho chiamato il tuo metodo, i miei metodi si bloccavano tutti. Se JavaScript può in qualche modo preservare il contesto di esecuzione della tua funzione, memorizzarlo da qualche parte, quindi riportarlo indietro e continuare in seguito, quindi potrebbe verificarsi il sonno, ma in pratica si tratta di threading.

Quindi sei praticamente bloccato con quello che gli altri hanno suggerito: dovrai rompere il tuo codice in più funzioni.

La tua domanda è un po 'una scelta sbagliata, quindi. Non c'è modo di dormire nel modo che vuoi, né dovresti perseguire la soluzione che suggerisci.

Question

C'è un modo migliore per programmare un sleep in JavaScript rispetto alla seguente funzione pausecomp ( presa da qui )?

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

Questo non è un duplicato di Sleep in JavaScript - ritardo tra le azioni ; Voglio un vero sonno nel mezzo di una funzione, e non un ritardo prima che un pezzo di codice venga eseguito.




Riesco a capire lo scopo di una funzione sleep se si ha a che fare con l'esecuzione sincrona. Le funzioni setInterval e setTimeout creano un thread di esecuzione parallelo che restituisce la sequenza di esecuzione al programma principale, che è inefficace se si deve attendere un determinato risultato. Naturalmente si possono usare eventi e gestori, ma in alcuni casi non è ciò che si intende.




Ecco qui. Come dice il codice, non essere un cattivo sviluppo e usarlo sui siti web. È una funzione di utilità di sviluppo.

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



Ho cercato / googled alcune pagine web su javascript sleep / wait ... e non c'è risposta se vuoi che javascript "RUN, DELAY, RUN" ... ciò che la maggior parte delle persone ha ottenuto è "RUN, RUN (inutile roba), RUN "o" RUN, RUN + delayed RUN "....

Così ho mangiato degli hamburger e ho pensato ::: ecco una soluzione che funziona ... ma devi tagliare i tuoi codici di marcia ... ::: sì, lo so, questo è solo un refactoring più facile da leggere .. ancora ...

//......................................... //Esempio 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>

// .................................... // esempio2:

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

// ................. esempio3:

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

// .............. esempio4:

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



Una soluzione migliore per far sembrare le cose ciò che la maggior parte della gente desidera utilizzare una funzione anonima:

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

Questo è probabilmente il più vicino a qualcosa che fa semplicemente quello che vuoi.

Nota, se hai bisogno di più posti letto, questo può diventare brutto in fretta e potresti dover effettivamente ripensare il tuo design.




An old question from 2009. Now in 2015 a new solution is possible with generators defined in ECMAscript 2015 aka ES6. It was approved in June, but it was implemented in Firefox and Chrome before. Now a sleep function can be made non-busy, non-blocking and nested inside loops and sub-functions without freezing the browser. Only pure JavaScript is needed, no libraries or frameworks.

The program below shows how sleep() and runSleepyTask() can be made. The sleep() function is only a yield statement. It is so simple that it is actually easier to write the yield statement directly in stead of calling sleep() , but then there would be no sleep-word :-) The yield returns a time value to the next() method inside wakeup() and waits. The actual "sleeping" is done in wakeup() using the good old setTimeout() . At callback the the next() method triggers the yield statement to continue, and the "magic" of yield is that all the local variables and the whole call-stack around it is still intact.

Functions that use sleep() or yield must be defined as generators. Easy done by adding an asterix to the keyword function* . To execute a generator is a bit trickier. When invoked with the keyword new the generator returns an object that has the next() method, but the body of the generator is not executed (the keyword new is optional and makes no difference). The next() method triggers execution of the generator body until it encounters a yield . The wrapper function runSleepyTask() starts up the ping-pong: next() waits for a yield , and yield waits a next() .

Another way to invoke a generator is with keyword yield* , here it works like a simple function call, but it also includes the ability to yield back to next() .

This is all demonstrated by the example drawTree() . It draws a tree with leaves on a rotating 3D scene. A tree is drawn as a trunk with 3 parts at the top in different directions. Each part is then drawn as another but smaller tree by calling drawTree() recursively after a short sleep. A very small tree is drawn as only a leaf.

Each leaf has its own life in a separate task started with runSleepyTask() . It is born, grows, sits, fades, falls and dies in growLeaf() . The speed is controlled with sleep() . This demonstrates how easy multitasking can be done.

function* sleep(milliseconds) {yield milliseconds};

function runSleepyTask(task) {
    (function wakeup() {
        var result = task.next();
        if (!result.done) setTimeout(wakeup, result.value);
    })()
}
//////////////// written by Ole Middelboe  /////////////////////////////

pen3D =setup3D();
var taskObject = new drawTree(pen3D.center, 5);
runSleepyTask(taskObject);

function* drawTree(root3D, size) {
    if (size < 2) runSleepyTask(new growLeaf(root3D))
    else {
        pen3D.drawTrunk(root3D, size);
        for (var p of [1, 3, 5]) {
            var part3D = new pen3D.Thing;
            root3D.add(part3D);
            part3D.move(size).turn(p).tilt(1-p/20);
            yield* sleep(50);
            yield* drawTree(part3D, (0.7+p/40)*size);
        }
    }
}

function* growLeaf(stem3D) {
    var leaf3D = pen3D.drawLeaf(stem3D);
    for (var s=0;s++<15;) {yield* sleep(100); leaf3D.scale.multiplyScalar(1.1)}
    yield* sleep( 1000 + 9000*Math.random() );
    for (var c=0;c++<30;) {yield* sleep(200); leaf3D.skin.color.setRGB(c/30, 1-c/40, 0)}
    for (var m=0;m++<90;) {yield* sleep( 50); leaf3D.turn(0.4).tilt(0.3).move(2)}
    leaf3D.visible = false;
}
///////////////////////////////////////////////////////////////////////

function setup3D() {
    var scene, camera, renderer, diretionalLight, pen3D;

    scene = new THREE.Scene();
    camera = new THREE.PerspectiveCamera(75, 
        window.innerWidth / window.innerHeight, 0.1, 1000);
    camera.position.set(0, 15, 20);
    renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);
    
    directionalLight = new THREE.DirectionalLight(0xffffaa, 0.7);
    directionalLight.position.set(-1, 2, 1);
    scene.add(directionalLight);
    scene.add(new THREE.AmbientLight(0x9999ff));
      
    (function render() {
        requestAnimationFrame(render);
        // renderer.setSize( window.innerWidth, window.innerHeight );
        scene.rotateY(10/60/60);
        renderer.render(scene, camera);
    })();
    
    window.addEventListener(
        'resize',
        function(){
            renderer.setSize( window.innerWidth, window.innerHeight );
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
       }, 
       false
    );
    
    pen3D = {
        drawTrunk: function(root, size) {
            // root.skin = skin(0.5, 0.3, 0.2);
            root.add(new THREE.Mesh(new THREE.CylinderGeometry(size/12, size/10, size, 16), 
                root.skin).translateY(size/2));
            root.add(new THREE.Mesh(new THREE.SphereGeometry(size/12, 16), 
                root.skin).translateY(size));
            return root;
        },
        
        drawLeaf: function(stem) {
            stem.skin.color.setRGB(0, 1, 0);
            stem.add(new THREE.Mesh(new THREE.CylinderGeometry(0, 0.02, 0.6), 
                stem.skin) .rotateX(0.3).translateY(0.3));
            stem.add(new THREE.Mesh(new THREE.CircleGeometry(0.2), 
                stem.skin) .rotateX(0.3).translateY(0.4));
            return stem;
        },
        
        Thing: function() {
            THREE.Object3D.call(this);
            this.skin = new THREE.MeshLambertMaterial({
                color: new THREE.Color(0.5, 0.3, 0.2),
                vertexColors: THREE.FaceColors,
                side: THREE.DoubleSide
            })
        }
    };

    pen3D.Thing.prototype = Object.create(THREE.Object3D.prototype);
    pen3D.Thing.prototype.tilt = pen3D.Thing.prototype.rotateX;
    pen3D.Thing.prototype.turn = pen3D.Thing.prototype.rotateY;
    pen3D.Thing.prototype.move = pen3D.Thing.prototype.translateY;
    
    pen3D.center = new pen3D.Thing;
    scene.add(pen3D.center);
    
    return pen3D;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r71/three.min.js"></script>

The 3D stuff is hidden inside setup3D() and is only included to make it less boring than console.log(). Angels are measured in radians by the way.

Tested to work in Firefox and Chrome. Not implemented in Internet Explore and iOS (iPads). Try to run it yourself.

After another pass of the answers I found, that Gabriel Ratener made a similar answer a year ago: https://.com/a/24401317/5032384




A lot of the answers don't (directly) answer the question, and neither does this one...

Here's my two cents (or functions):

If you want less clunky functions than setTimeout and setInterval , you can wrap them in functions that just reverse the order of the arguments and give them nice names:

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

CoffeeScript versions:

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

You can then use them nicely with anonymous functions:

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

Now it reads easily as "after N milliseconds, ..." (or "every N milliseconds, ...")




For the specific case of wanting to space out a set of calls being executed by a loop, you can use something like the code below with prototype. Without prototype, you can substitute the delay function with 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)
}



Solo per debug / dev , inserisco questo se è utile a qualcuno

Cose interessanti, in Firebug (e probabilmente in altre console js), non succede nulla dopo aver premuto enter, solo dopo che la durata del sonno è stata specificata (...)

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

Esempio di utilizzo:

function sleepThenAct(){ sleepFor(2000); console.log("hello js sleep !"); }



Primo:

Definire una funzione che si desidera eseguire in questo modo:

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

Quindi pianifica la sua esecuzione con il metodo setTimeout:

setTimeout(alertWorld,1000)

Nota due cose

  • il secondo argomento è il tempo in millisecondi
  • come primo argomento devi passare solo il nome (riferimento) della funzione, senza parentesi



Per i browser, sono d'accordo sul fatto che setTimeout e setInterval sono la strada da percorrere.

Ma per il codice lato server, potrebbe richiedere una funzione di blocco (ad esempio, in modo da poter effettivamente avere la sincronizzazione dei thread).

Se stai usando node.js e meteora, potresti aver incontrato i limiti dell'uso di setTimeout in una fibra. Ecco il codice per il sonno lato server.

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

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




Il codice preso da questo link non bloccherà il comp. Ma funziona solo su ff.

    /**
 * Netscape compatible WaitForDelay function.
 * You can use it as an alternative to Thread.Sleep() in any major programming language
 * that support it while JavaScript it self doesn't have any built-in function to do such a thing.
 * parameters:
 * (Number) delay in millisecond
*/
function nsWaitForDelay(delay) {
/**
  * Just uncomment this code if you're building an extention for Firefox.
  * Since FF3, we'll have to ask for user permission to execute XPCOM objects.
  */
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");

// Get the current thread.
var thread = Components.classes["@mozilla.org/thread-manager;1"].getService(Components.interfaces.nsIThreadManager).currentThread;

// Create an inner property to be used later as a notifier.
this.delayed = true;

/* Call JavaScript setTimeout function
  * to execute this.delayed = false
  * after it finish.
  */
setTimeout("this.delayed = false;", delay);

/**
  * Keep looping until this.delayed = false
  */
while (this.delayed) {
/**
  * This code will not freeze your browser as it's documented in here:
  * https://developer.mozilla.org/en/Code_snippets/Threads#Waiting_for_a_background_task_to_complete
  */
thread.processNextEvent(true);
}
}



One scenario where you might want a sleep() function rather than using setTimeout() is if you have a function responding to a user click that will ultimately end up opening a new ie popup window and you have initiated some processing that requires a short period to complete before the popup is displayed. Moving the open window into a closure means that it typically gets blocked by the browser.




Se stai usando jQuery, qualcuno ha effettivamente creato un plugin "delay" che non è altro che un wrapper per 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;
};

Puoi quindi semplicemente usarlo in una fila di chiamate di funzione come previsto:

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



So che questa è una domanda un po 'vecchia, ma se (come me) stai usando Javascript con Rhino, puoi usare ...

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



Related