Qu'est-ce que la version JavaScript de sleep()?

y a-t-il une meilleure façon de concevoir un sleep en JavaScript que la fonction suivante pausecomp ( d'ici )?

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

ce N'est pas une copie de Sleep in JavaScript - delay between actions ; je veux un real sleep au milieu d'une fonction, et pas un délai avant qu'un morceau de code s'exécute.

1599
demandé sur fmsf 2009-06-04 18:41:10

30 réponses

mise à jour 2017

depuis 2009, date à laquelle cette question a été posée, JavaScript a considérablement évolué. Toutes les autres réponses sont désormais obsolètes ou trop compliquées. Voici la meilleure pratique actuelle:

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

demo();

on y est. await sleep(<duration>) .

vous pouvez essayer ce code live sur Runkit . Notez que,

  1. await peut ne s'exécute que dans les fonctions préfixées par le mot-clé async . Runkit enroule votre code dans une fonction async avant de l'exécuter.
  2. await arrête seulement la fonction actuelle async 1519300920"

deux nouvelles fonctionnalités JavaScript ont aidé à écrire cette fonction "sommeil":

compatibilité

si, pour une raison quelconque, vous utilisez un noeud de plus de 7 ans, ou si vous ciblez d'anciens navigateurs, async / await peut encore être utilisé via Babel (un outil qui sera transpile JavaScript + nouvelles fonctionnalités dans L'Ancien JavaScript), avec le transform-async-to-generator plugin . Run

npm install babel-cli --save

créer .babelrc avec:

{
  "plugins": [
    "transform-async-to-generator",
  ]
}

puis lancez votre code avec

node_modules/babel-cli/bin/babel-node.js sleep.js

mais encore une fois, vous n'avez pas besoin de cela si vous utilisez le noeud 7 ou plus tard, ou si vous êtes cibler les navigateurs modernes.

1211
répondu Dan Dascalescu 2018-09-05 06:00:44

(voir la" réponse mise à jour pour 2016 )

je pense qu'il est parfaitement raisonnable d'en souhaitez effectuer une action, attendre, puis effectuer une autre action. Si vous êtes habitué à écrire dans des langues multi-threadées, vous avez probablement l'idée de céder l'exécution pour un certain temps jusqu'à ce que votre thread se réveille.

le problème ici est que JavaScript est un modèle basé sur un seul thread. Alors que dans un cas spécifique, il pourrait être sympa d'avoir l'ensemble du moteur, attendre quelques secondes, en général, c'est une mauvaise pratique. Supposons que je veuille utiliser vos fonctions tout en écrivant les miennes? Quand j'ai appelé ta méthode, toutes mes méthodes se figeaient. Si JavaScript pouvait d'une façon ou d'une autre préserver le contexte d'exécution de votre fonction, le stocker quelque part, puis le ramener et continuer plus tard, alors le sommeil pourrait se produire, mais ce serait essentiellement filetage.

donc vous êtes assez coincé avec ce que d'autres ont suggéré -- vous aurez besoin de casser votre code en plusieurs fonctions.

Votre question est un peu un faux choix, puis. Il n'y a aucun moyen de dormir comme vous le voulez, et vous ne devriez pas chercher la solution que vous suggérez.

830
répondu Ben Flynn 2017-05-23 12:18:28

en JavaScript, je réécris chaque fonction pour qu'elle se termine le plus tôt possible. Vous voulez que le navigateur reprenne le contrôle afin qu'il puisse faire vos changements de DOM.

chaque fois que j'ai voulu dormir au milieu de ma fonction, j'ai refactorisé pour utiliser un setTimeout() .

je vais éditer cette réponse parce que je l'ai trouvé utile:

l'infâme fonction sommeil, ou délai, dans n'importe quelle langue est beaucoup débattu. Certains diront qu'il devrait toujours y avoir un signal ou un rappel pour lancer une fonctionnalité donnée, d'autres diront que parfois un moment arbitraire de retard est utile. Je dis qu'à chacun sa propre et une règle ne peut jamais dicter quoi que ce soit dans cette industrie.

écrire une fonction de sommeil est simple et encore plus utilisable avec les promesses JavaScript:

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

// Usage!
sleep(500).then(() => {
    // Do something after the sleep!
});
597
répondu gsamaras 2016-09-15 08:57:09

Uniquement pour le débogage/dev , je poste ceci si c'est utile à quelqu'un

chose intéressante, dans Firebug (et probablement d'autres consoles js ), rien ne se passe après avoir frappé enter, seulement après la durée de sommeil spécifiée (...)

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

exemple d'utilisation:

function sleepThenAct(){ sleepFor(2000); console.log("hello js sleep !"); }
270
répondu StephaneAG 2017-11-10 13:41:14

je suis d'accord avec les autres posters, une longue nuit de sommeil est une mauvaise idée.

cependant, setTimeout ne retarde pas l'exécution, il exécute la ligne suivante de la fonction immédiatement après que le timeout est réglé, et non après que le timeout expire, de sorte qu'il n'accomplit pas la même tâche qu'un sommeil accomplirait.

la façon de le faire est de décomposer votre fonction en parties avant et après.

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

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

assurez-vous vos noms de fonction décrivent toujours avec précision ce que chaque pièce fait (C'est-à-dire GatherInputThenWait et Chectinput, plutôt que funcPart1 et funcPart2)

Modifier

cette méthode atteint le but de ne pas exécuter les lignes de code que vous décidez avant après votre timeout, tout en retournant le contrôle de nouveau au PC client pour exécuter quoi que ce soit d'autre qu'il a mis en file d'attente.

Modifier

comme indiqué dans les commentaires, cela ne fonctionnera absolument pas en boucle. Vous pourriez faire un peu de piratage Fantaisie (laid) pour le faire fonctionner dans une boucle, mais en général, cela ne fera que le code spaghetti désastreux.

166
répondu DevinB 2009-06-10 18:52:41

pour l'amour de $DEITY s'il vous plaît ne pas faire une fonction de sommeil d'attente occupé. setTimeout et setInterval font tout ce dont vous avez besoin.

114
répondu chaos 2014-09-11 20:59:44

je sais que c'est un peu une vieille question, mais si (comme moi) vous utilisez Javascript avec Rhino, vous pouvez utiliser...

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.
   */
}
110
répondu mjaggard 2011-11-04 14:16:06

si vous utilisez jQuery, quelqu'un a en fait créé un plugin "delay" qui n'est rien de plus qu'un wrapper pour 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;
};

Vous pouvez ensuite l'utiliser dans une ligne d'appels de fonction comme prévu:

$('#warning')
.addClass('highlight')
.delay(1000)
.removeClass('highlight');
65
répondu Alan Plum 2009-06-10 18:50:32

j'ai cherché la solution de sommeil aussi (pas pour le code de production, seulement pour dev/tests) et j'ai trouvé cet article:

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

...et voici un autre lien avec les solutions côté client: http://www.devcheater.com /

en outre, lorsque vous appelez alert() , votre code sera mis en pause aussi, alors que l'alerte est montré -- besoin de trouver un moyen de ne pas afficher l'alerte, mais obtenir le même effet. :)

42
répondu a_w 2016-09-06 07:26:05

voilà. Comme le code le dit, ne soyez pas un mauvais dev et utilisez ceci sur les sites web. C'est une fonction de développement utilitaire.

// 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) {}
}
29
répondu Ian Maddox 2012-11-03 02:02:47

Voici une solution simple utilisant une XMLHttpRequest synchrone:

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

contenu du sommeil.php:

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

appelez maintenant avec: sleep (5);

25
répondu pguardiario 2016-03-13 01:42:38

d'Abord:

définissez une fonction que vous voulez exécuter comme ceci:

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

puis programmer son exécution avec la méthode setTimeout:

setTimeout(alertWorld,1000)

Note deux choses

  • le deuxième argument est le temps en millisecondes
  • comme premier argument vous devez passer juste le nom (référence) de la fonction, sans la parenthèse
15
répondu Pablo Fernandez 2009-06-04 14:47:52

j'aime personnellement le simple:

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

puis:

sleep(2); // Sleeps for 2 seconds

Je l'utilise tout le temps pour créer de faux temps de chargement tout en créant des scripts dans P5js

15
répondu Akelian 2016-11-12 19:56:33

meilleure solution pour faire ressembler les choses à ce que la plupart des gens veulent est d'utiliser une fonction anonyme:

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

c'est probablement ce qui se rapproche le plus de quelque chose qui fait simplement ce que vous voulez.

Note, Si vous avez besoin de plusieurs lits cela peut devenir laid à la hâte et vous pourriez en fait avoir besoin de repenser votre conception.

12
répondu Mainguy 2011-08-08 13:05:30

j'encapsulerais setTimeOut dans une promesse de cohérence du code avec d'autres tâches asynchrones : Démo dans Fiddle

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

utilisé comme ça:

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

il est facile de se rappeler la syntaxe si vous utilisiez des promesses.

9
répondu Elo 2015-07-09 13:59:21

pour les navigateurs, je suis d'accord que setTimeout et setInterval sont la voie à suivre.

mais pour le code côté serveur, il peut exiger une fonction de blocage (par exemple, de sorte que vous pouvez effectivement avoir la synchronisation de thread).

si vous utilisez node.js et meteor, vous avez exécuté dans les limites de l'utilisation de setTimeout dans une fibre. Voici le code côté serveur sommeil.

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

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

8
répondu Homer6 2013-05-17 22:53:18

la Plupart des réponses ici sont erronées ou à tout le moins obsolète. Il n'y a pas de raison pour que javascript doive être un seul thread, et ce n'est pas le cas. Aujourd'hui, tous les navigateurs mainstream prennent en charge les travailleurs, avant cela était le cas d'autres durées d'exécution javascript comme Rhino et noeud.js a pris en charge le multithreading.

'Javascript est mono-thread" n'est pas une réponse valable. Par exemple, exécuter une fonction de sommeil au sein d'un travailleur ne bloquerait pas le fonctionnement d'un code dans l'interface utilisateur. fil.

dans les nouvelles durées d'exécution supportant les générateurs et le rendement, on pourrait apporter une fonctionnalité similaire à la fonction de sommeil dans un environnement fileté simple:

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

cette imitation du sommeil est différente d'une véritable fonction de sommeil car elle ne bloque pas le fil. C'est tout simplement du sucre en plus de la fonction setTimeout actuelle de javascript. Ce type de fonctionnalité a été implémenté dans la tâche .js et devrait travailler aujourd'hui en Firefox.

8
répondu Gabriel Ratener 2014-10-16 08:22:24

j'ai cherché/googlé plusieurs pages Web sur JavaScript sleep/wait... et il n'y a pas de réponse si vous voulez javascript pour "exécuter, retarder, exécuter"... ce que la plupart des gens obtenaient était "RUN, RUN(useless stuff), RUN" ou "RUN, RUN + delayed RUN"....

alors j'ai mangé des hamburgers et j'ai réfléchi::: voici une solution qui fonctionne... mais tu dois découper tes codes...::: oui, je sais, c'est juste un plus facile à lire refactoring... encore...

//......................................... // exemple1:

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

//.................................... // exemple2:

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

//................. exemple3:

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

//.............. exemple4:

<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>
7
répondu user207408 2009-11-10 06:06:23
function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if ((new Date().getTime() - start) > milliseconds){
      break;
    }
  }
}
7
répondu Shemeer M Ali 2013-11-09 18:37:54

je peux comprendre le but d'une fonction de sommeil si vous avez affaire à l'exécution synchrone. Les fonctions setInterval et setimeout créent un thread d'exécution parallèle qui renvoie la séquence d'exécution au programme principal, ce qui est inefficace si vous devez attendre un résultat donné. Bien sûr, on peut utiliser les événements et les gestionnaires, mais dans certains cas, n'est pas ce qui est prévu.

6
répondu naazgull 2011-06-21 17:41:26

un scénario où vous pourriez vouloir une fonction sleep() plutôt que d'utiliser setTimeout() est si vous avez une fonction répondant à un clic de l'utilisateur qui finira par ouvrir une nouvelle fenêtre c.-à-d. popup et vous avez initié un traitement qui nécessite une courte période à compléter avant que le popup soit affiché. Déplacer la fenêtre ouverte dans une fermeture signifie qu'elle est généralement bloquée par le navigateur.

5
répondu acuth 2010-10-18 19:45:43

ajoute mes deux cents. J'avais besoin d'une longue attente pour les tests. Je ne voulais pas partager le code car ce serait beaucoup de travail, donc un simple pour l'a fait pour moi.

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

je ne vois aucun inconvénient à le faire et ça a fait l'affaire pour moi.

5
répondu caiocpricci2 2012-12-20 11:57:30

il peut être fait en utilisant la méthode de sommeil de Java. Je l'ai testé en FF et IE et il ne ferme pas l'ordinateur, ne mâche pas les ressources, ou ne cause pas de visites interminables du serveur. Semble comme une solution propre pour moi.

vous devez d'abord charger Java sur la page et rendre ses méthodes disponibles. Pour faire cela, j'ai fait ceci:

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

alors, tout ce que vous avez à faire quand vous voulez une pause indolore dans votre JS est:

java.lang.Thread.sleep(xxx)

où xxx est le temps en millisecondes. Dans mon cas (à titre de justification), cela faisait partie de l'exécution des commandes à l'arrière-plan dans une très petite entreprise et j'avais besoin d'imprimer une facture qui devait être chargée à partir du serveur. Je l'ai fait en chargeant la facture (comme une page Web) dans une iFrame puis en imprimant l'iFrame. Bien sûr, j'ai dû attendre jusqu'à ce que la page soit entièrement chargée avant de pouvoir imprimer, donc le JS a dû faire une pause. J'ai fait cela en demandant à la page de facture (dans l'iFrame) de changer un champ de formulaire caché sur le page parent avec l'événement onLoad. Et le code sur la page mère pour imprimer la facture ressemblait à ceci (pièces non pertinentes coupées pour plus de clarté):

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

ainsi l'utilisateur appuie sur le bouton, le script charge la page de facture, puis attend, vérifiant chaque quart de seconde pour voir si la page de facture est terminée chargement, puis apparaît la boîte de dialogue d'impression pour l'utilisateur de l'Envoyer à l'imprimante. QED.

5
répondu Rachael 2013-01-14 01:32:07

beaucoup de réponses ne répondent pas (directement) à la question, et celle-ci non plus...

Voici mes deux cents (ou fonctions):

si vous voulez moins de fonctions clunky que setTimeout et setInterval , vous pouvez les envelopper dans des fonctions qui renversent juste l'ordre des arguments et leur donnent de beaux noms:

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

vous pouvez alors les utiliser bien avec les fonctions anonymes:

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

maintenant il se lit facilement comme " après N millisecondes,..."(ou "toutes les N millisecondes ...")

5
répondu 1j01 2016-07-16 03:41:10

vous ne pouvez pas dormir comme ça en JavaScript, ou plutôt, vous ne devriez pas. L'exécution d'une boucle sleep ou while causera la suspension du navigateur de l'utilisateur jusqu'à ce que la boucle soit terminée.

utilisez une minuterie, comme spécifié dans le lien que vous avez mentionné.

4
répondu Andrew Dunkman 2009-06-04 14:46:51

pour le cas spécifique de vouloir espacer un ensemble d'appels étant exécutés par une boucle, vous pouvez utiliser quelque chose comme le code ci-dessous avec prototype. Sans prototype, vous pouvez remplacer la fonction delay par 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)
}
4
répondu beauburrier 2010-05-27 19:45:00

si vous êtes sur le noeud.js, vous pouvez jeter un oeil à fibres – une extension C natif de noeud, une sorte de simulation multi-threading.

Cela permet de faire un vrai sleep d'une manière qui est bloquant l'exécution dans une fibre, mais c'est non-bloquant dans le thread principal et d'autres fibres.

voici un exemple récent de leur propre readme:

// 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');
"151930920 – - et les résultats sont:

$ 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)
4
répondu tomekwi 2015-02-06 10:55:38

une vieille question de 2009. Maintenant en 2015 une nouvelle solution est possible avec des générateurs définis dans ECMAscript 2015 alias ES6. Il a été approuvé en juin, mais il a été mis en œuvre dans Firefox et Chrome Avant. Maintenant, une fonction de sommeil peut être rendue non-occupé, non-blocage et imbriqué à l'intérieur des boucles et des sous-fonctions sans gel du navigateur. Seul le JavaScript pur est nécessaire, pas de bibliothèques ou de cadres.

Le programme ci-dessous montre comment sleep() et runSleepyTask() peut être faire. La fonction sleep() n'est qu'une instruction yield . Il est si simple qu'il est en fait plus facile d'écrire la déclaration yield directement au lieu d'appeler sleep() , mais alors il n'y aurait pas de mot sommeil: -) le rendement renvoie une valeur de temps à la méthode next() à l'intérieur de wakeup() et attend. Le "sommeil" réel est fait dans wakeup() en utilisant le bon vieux setTimeout() . Au rappel, la méthode next() déclenche l'instruction yield vers continuez, et la "magie" du rendement est que toutes les variables locales et toute la pile d'appels autour de lui sont encore intactes.

les fonctions qui utilisent le sommeil() ou le rendement doivent être définies comme des générateurs. Facile à faire en ajoutant un Astérix au mot-clé function* . Pour exécuter un générateur est un peu plus compliqué. Lorsqu'il est invoqué avec le mot-clé new le générateur renvoie un objet qui a la méthode next() , mais le corps du générateur n'est pas exécuté (le mot-clé new est facultatif et ne fait aucune différence). La méthode next() déclenche l'exécution du corps du générateur jusqu'à ce qu'il rencontre un yield . La fonction d'enrubannage runSleepyTask() démarre le ping-pong: next() attend un yield , et yield attend un next() .

une autre façon d'invoquer un générateur est avec le mot-clé yield* , ici il fonctionne comme un simple appel de fonction, mais il inclut également la capacité de céder en arrière à next() .

tout cela est démontré par l'exemple drawTree() . Il dessine un arbre avec des feuilles sur une scène 3D rotative. Un arbre est dessiné comme un tronc avec 3 pièces en haut dans des directions différentes. Chaque partie est alors dessinée comme un autre mais plus petit arbre en appelant drawTree() récursivement après un court sommeil. Un très petit arbre est dessiné comme seulement une feuille.

chaque feuille a sa propre vie dans une tâche séparée commencée avec runSleepyTask() . Il est naît, croît, s'assied, s'arrête, tombe et meurt dans growLeaf() . La vitesse est contrôlée par sleep() . Cela montre à quel point le multitâche peut être facile.

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>

le truc 3D est caché à l'intérieur de setup3D() et n'est inclus que pour le rendre moins ennuyeux que la console.journal.)( Les anges sont mesurés en radians d'ailleurs.

testé pour fonctionner dans Firefox et Chrome. Non implémenté sur Internet Explorer et iOS (iPads). Essayez d'exécuter vous-même.

après un autre passage des réponses que J'ai trouvé, que Gabriel Ratener a fait une réponse similaire il y a un an: https://stackoverflow.com/a/24401317/5032384

4
répondu Ole Middelboe 2017-05-23 12:26:35

tout d'abord-setTimeout et setInterval est ce que devrait être utilisé, en raison de la nature callback-ish de javascript. Si vous voulez utiliser sleep() c'est le flux de contrôle ou l'architecture de votre code qui est incorrect.

ayant dit que je suppose que je peux encore aider avec deux implémentation du sommeil.

  1. simulation synchrone exécuter sur le dessus de ma tête:

    //a module to do taht //dual-license: MIT or WTF [you can use it anyhow and leave my nickname in a comment if you want to]
    var _=(function(){
     var queue=[];
     var play=function(){
       var go=queue.shift();
         if(go){if(go.a){go.f();play();}else{setTimeout(play,go.t);}}
       }
     return {
       go:function(f){
        queue.push({a:1,f:f});
        },
       sleep:function(t){
        queue.push({a:0,t:t});
        },
       playback:play 
     }
    })();
    

    [rend la lecture automatique devrait également être possible]

    //usage
    
    _.go(function(){
    
    //your code
    console.log('first');
    
    });
    
    
    _.sleep(5000);
    
    _.go(function(){
    
    //your code
    console.log('next');
    
    });
    
    //this triggers the simulation
    _.playback();
    
  2. real synchrone run

j'y ai beaucoup réfléchi un jour et la seule idée que j'avais pour un vrai sommeil en javascript est technique.

une fonction de sommeil devrait être un appel synchrone AJAX avec un temps d'arrêt réglé à la valeur de sommeil. C'est tout et une seule façon d'avoir une real sleep()

3
répondu naugtur 2011-08-09 08:53:48

si vous corrigez une fonction de sommeil comme celle-ci

var sleep = function(period, decision, callback){
    var interval = setInterval(function(){
        if (decision()) {
            interval = clearInterval(interval);
            callback();
        }
    }, period);
}

et vous avez une fonction asynchrone pour appeler plusieurs fois

var xhr = function(url, callback){
    // make ajax request
    // call callback when request fulfills
}

et vous configurez votre projet comme ceci:

var ready = false;

function xhr1(){
    xhr(url1, function(){ ready = true;});  
}
function xhr2(){
    xhr(url2, function(){ ready = true; }); 
}
function xhr3(){
    xhr(url3, function(){ ready = true; }); 
}

alors vous pouvez faire ceci:

xhr1();
sleep(100, function(){ return done; }, xhr2);
sleep(100, function(){ return done; }, xhr3);
sleep(100, function(){ return done; }, function(){
    // do more
});

au lieu de l'indentation sans fin comme ceci:

xhr(url1, function(){
    xhr2(url2, function(){
        xhr3(url3, function(){
            // do more
        });
    });
});
3
répondu BishopZ 2013-07-29 21:20:11