Quelle est la version JavaScript de sleep ()?

2339

Existe-t-il un meilleur moyen de créer un sleepfichier JavaScript que la pausecompfonction suivante ( prise ici )?

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

Ce n'est pas un doublon de Sleep in JavaScript - délai entre les actions ; Je veux un vrai sommeil au milieu d'une fonction, et non pas un délai avant qu'un morceau de code ne s'exécute.

fmsf
la source
4
C'est à définir au milieu d'un certain temps, si j'utilise setTimeout, le temps continuera à traiter et à mettre en file d'attente plus de setTimeouts qui finiront par fonctionner en même temps et
créeront
160
C'est une solution horrible - vous allez ralentir les cycles de traitement sans rien faire.
17 de 26
12
Le seul but d'un sommeil est d'interroger ou d'attendre un rappel - setInterval et setTimeout font tous les deux mieux que cela.
annakata
1
Vous pouvez probablement faire ce que vous voulez avec le style de passage de continuation en JavaScript. Jetez un œil à cet article.
Ognyan Dimitrov

Réponses:

2566

Mise à jour 2017-2019

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

Ça y est. await sleep(<duration>).

Ou en monoplace:

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

Notez que,

  1. awaitne peut être exécuté que dans des fonctions préfixées par le asyncmot - clé, ou au niveau supérieur de votre script dans certains environnements (par exemple la console Chrome DevTools ou Runkit).
  2. awaitsuspend uniquement la asyncfonction actuelle

Deux nouvelles fonctionnalités JavaScript ont aidé à écrire cette fonction "veille":

Compatibilité

Si, pour une raison étrange, vous utilisez Node plus de 7 (qui a atteint la fin de sa vie ), ou ciblez d'anciens navigateurs, async/ awaitpeut toujours être utilisé via Babel (un outil qui transposera JavaScript + de nouvelles fonctionnalités en ancien JavaScript). , avec le transform-async-to-generatorplugin.

Dan Dascalescu
la source
5
Super truc ici. Je me demande, comment cela affecte-t-il ou se rapporte-t-il aux états "actifs" / "inactifs" des navigateurs modernes après que JS ait appelé le mode "veille"? Le navigateur peut-il bloquer le sommeil comme prévu pour le JS général, pour se rappeler plus tard quand devient "actif", ou a-t-il un comportement différent?
Andre Canilho
18
Quelle est la prise en charge actuelle du navigateur pour cela? Je ne considérerais pas les solutions précédentes comme "obsolètes" jusqu'à ce que cette solution soit prise en charge par la grande majorité des navigateurs, ou du moins tous les navigateurs courants. Au contraire, je considérerais cette solution intéressante mais inutilisable / peu pratique jusqu'à ce qu'elle bénéficie d'un large soutien.
Alvin Thompson
75
Ce n'est pas du "vrai sommeil" et ne répond pas à la question. La personne qui a demandé a clairement fait la distinction entre stackoverflow.com/questions/758688/sleep-in-javascript et sa question. En veille réelle, aucun autre code ne peut être exécuté (sauf dans un autre thread). Cette réponse est bonne pour l'autre question.
2017
4
@jacroe - le transpilateur gère les fonctions fléchées ainsi que l'async / wait (ce qui ferait quand même vomir du sang à IE)
Jaromanda X
11
@niry JavaScript, étant un langage à un seul thread, n'est pas bien adapté au sommeil "réel", car il s'exécute sur le même thread que l'interface utilisateur et provoquerait des pages Web qui ne répondent pas.
Patrick Roberts
849

(Voir la réponse mise à jour pour 2016 )

Je pense qu'il est parfaitement raisonnable de vouloir effectuer une action, attendre, puis effectuer une autre action. Si vous avez l'habitude d'écrire dans des langages multithreads, vous avez probablement l'idée de céder l'exécution pendant un certain temps jusqu'à ce que votre thread se réveille.

Le problème ici est que JavaScript est un modèle basé sur des événements à un seul thread. Alors que dans un cas spécifique, il peut être agréable de laisser le moteur entier attendre quelques secondes, en général c'est une mauvaise pratique. Supposons que je veuille utiliser vos fonctions tout en écrivant les miennes? Lorsque j'appelais votre méthode, mes méthodes se bloquaient toutes. Si JavaScript pouvait en quelque sorte 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 du filetage.

Donc, vous êtes à peu près coincé avec ce que d'autres ont suggéré - vous devrez diviser votre code en plusieurs fonctions.

Votre question est donc un peu un faux choix. Il n'y a aucun moyen de dormir comme vous le souhaitez et vous ne devez pas non plus poursuivre la solution que vous proposez.

Ben Flynn
la source
45
Ce n'est pas du tout une bonne réponse. Si Javascript n'a pas de fonction de veille, c'est uniquement parce que ECMAScript ne l'exige pas. Il s'agit d'un choix de conception par l'organisme responsable de la conception de Javascript. Il aurait pu être fait que le temps d'exécution Javascript attend un certain temps avant d'exécuter la ligne de code suivante, mais il a été choisi de ne pas le faire.
Didier A.
5
Un sommeil peut être parfaitement implémenté en JavaScript, mais pas avec une précision en temps réel. Après tout, c'est un système basé sur les événements. Si les appels asynchrones sont terminés, un événement est déclenché. Je ne vois aucune raison pour laquelle la même chose ne peut pas être possible quand un sleep () est émis, après quoi le contrôle est retourné au navigateur jusqu'à ce que le sommeil soit terminé, retournant le contrôle à la fonction appelante. Et oui, je conviens également que parfois dormir est pratique, surtout lorsque les développeurs AVANT de foirer le design si mal que VOUS n'avez pas d'autre issue que de refactoriser complètement pour lequel vous n'avez pas le temps
Lawrence
Essayez Hypnotic, qui suit cette idée: coolwanglu.github.io/hypnotic/web/demo.html
Tezcat
4
Appeler javascript single-threaded est un mythe. Bien qu'il puisse être techniquement correct, il fonctionne fonctionnellement comme un langage multithread. Simuler un fork () est trivialement facile, et bien que yield () ne soit pas vraiment implémentable, vous pouvez vous rapprocher en utilisant la mémoire partagée pour verrouiller / sémaphore. Pour le programmeur moyen, il est logique de le traiter comme multithread; le nom technique ne compte que pour les développeurs de la langue.
Benubird
8
Je suis d'accord pourquoi ce sleep()n'est pas possible dans JS, et que la plupart du temps il y a de meilleures façons de faire les choses. Mais je considérerais toujours la façon dont le moteur lie toutes choses comme un défaut de conception; il n'y a aucune raison que la langue ne puisse pas avoir une sleep()fonction limitée à un script, une page ou une fonction spécifique sans que le moteur n'encombre le CPU et ne gèle l'application comme un maniaque. Nous sommes en 2015 et vous ne devriez pas pouvoir planter un navigateur Web entier avec while(1). Nous avons Flash pour des choses comme ça.
Beejor
660

En JavaScript, je réécris chaque fonction pour qu'elle se termine le plus rapidement possible. Vous voulez que le navigateur reprenne le contrôle afin qu'il puisse apporter vos modifications DOM.

Chaque fois que je voulais dormir au milieu de ma fonction, je refactorisais d'utiliser un setTimeout().

Éditer

La fameuse fonction de sommeil ou de retard dans n'importe quelle langue est très controversée. Certains diront qu'il devrait toujours y avoir un signal ou un rappel pour déclencher une fonctionnalité donnée, d'autres diront que parfois un moment de retard arbitraire est utile. Je dis qu'à chacun sa règle et qu'une règle ne peut jamais dicter quoi que ce soit dans cette industrie.

L'écriture d'une fonction de veille est simple et encore plus utilisable avec 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!
});
gsamaras
la source
190
En guise de fermeture. function foobar(el) { setTimeout(function() { foobar_cont(el); }, 5000); }
chaos
68
ok, et si le code n'est pas destiné à être utilisé dans une page Web?
Eugenio Miró
10
@ EugenioMiró si le code n'est pas destiné à être utilisé dans une page Web, demandez au modèle objet de l'hôte de mettre en œuvre une méthode de mise en veille. - Je pense que la question est orientée vers le DOM qui est exposé au javascript exécuté sur les pages Web.
BrainSlugs83
31
@Nosredna oui, nous comprenons comment faire des appels asynchrones, cela ne nous aide pas à dormir (). Je veux que mes appels soient passés dans un certain ordre et que les données soient de retour dans un certain ordre. Je suis à 5 niveaux dans une boucle for. Je veux BLOQUER l'exécution. Une vraie méthode de veille ne "ralentirait pas le navigateur", les mains de veille reviennent au navigateur et à tous les autres threads qui veulent du temps CPU alors qu'il est toujours bloquant.
BrainSlugs83
382
ce n'est pas une réponse à la question.
TMS
303

Uniquement pour debug / dev , je poste ceci si c'est utile à quelqu'un

Des choses intéressantes, dans Firebug (et probablement d'autres consoles js), rien ne se passe après avoir appuyé sur 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 !"); }
StephaneAG
la source
36
Ce n'est pas une réponse. C'est exactement le même que le code dans la question, sauf légèrement plus court.
jab
16
Attente occupée, vraiment? Dans JS? Pendant des secondes? Si j'attrape un site Web faisant cela, il sera bloqué.
mafu
35
@mafu Voilà pourquoi il est dit only for debug/dev... rolleyes
xDaizu
12
NE FAITES JAMAIS CECI. Cela fera que le CPU atteindra 100% sur le cœur qu'il exécute et le bloquera.
noego
3
C'est utile, et peut-être la SEULE façon de dormir, dans une application javascript en ligne de commande, car async / wait n'est pas utile.
Wheezil
177

Je suis d'accord avec les autres affiches, un sommeil occupé n'est qu'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 délai d'expiration est défini, pas après l'expiration du délai d'expiration, de sorte que 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 que les noms de vos fonctions décrivent toujours avec précision ce que fait chaque élément (IE GatherInputThenWait et CheckInput, plutôt que funcPart1 et funcPart2)

Éditer

Cette méthode atteint l'objectif de ne pas exécuter les lignes de code que vous décidez jusqu'à APRÈS votre délai d'expiration, tout en renvoyant le contrôle au PC client pour exécuter tout ce qu'il a mis en file d'attente.

Modifier davantage

Comme indiqué dans les commentaires, cela ne fonctionnera absolument PAS en boucle. Vous pouvez faire un piratage sophistiqué (moche) pour le faire fonctionner en boucle, mais en général, cela ne fera que créer un code de spaghetti désastreux.

DevinB
la source
12
Ouais. Lorsque cela devient difficile, c'est quand vous avez une boucle, ou même une boucle imbriquée. Vous devez abandonner vos boucles for et avoir des compteurs à la place.
Nosredna
Touché. Je veux dire, ce serait toujours possible, mais laid et hackish dans ce cas. Vous pouvez également utiliser des variables d'état booléennes statiques, mais c'est aussi assez hackish.
DevinB
2
-1 pour cela. Encore une fois, cela ne répond pas à la question. Il s'agit plus d'une réponse à une question comme "Comment exécuter une fonction de manière asynchrone" qui est très différente de "Comment bloquer l'exécution d'un code".
Deepak GM
6
@Nosredna Non, vous utiliseriez une fermeture. Par exemple: function foo(index) { setTimeout(function() { foo_continue(index); }, 10000); }et for(var X = 0; X < 3;X++) { foo(X); }- la valeur de X est passée dans foo, qui est ensuite réutilisée sous le nom indexlorsqu'elle foo_continueest finalement appelée.
Izkata
2
@Alexander Bien sûr que oui, car le but de setTimeout () est d'empêcher le navigateur de se verrouiller en exécutant le code de manière asychronique. Mettez l' console.log()intérieur foo_continue()dans la version setTimeout et vous obtenez le même résultat.
Izkata
132

Pour l'amour de $ DEITY, ne faites pas de fonction de veille d'attente. setTimeoutet setIntervalfaites tout ce dont vous avez besoin.

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

Toutes les deux secondes, masquez le texte pendant une seconde. Cela montre comment utiliser setInterval et setTimeout pour afficher et masquer le texte chaque seconde.

Philip Rego
la source
3
Eh bien, pas tout: setInterval donne une bien meilleure impression du sondage.
annakata
3
Qu'est-ce que ce morceau de code ne retiendrait pas dans le moteur JavaScript?
Deniz Dogan
10
Sauf si vous avez besoin que le sommeil soit synchrone, auquel cas c'est une question tout à fait valable.
Aaron Dufour
36
Je pense que beaucoup d'entre nous oublient peut-être que JavaScript n'est pas un langage réservé aux navigateurs. Ce mec pourrait créer un utilitaire de ligne de commande Node qui nécessite une brève pause sans avoir à traiter tous les problèmes de portée de variable qui viennent avec setTimeout.
Phil LaNasa
3
@PhilLaNasa: Si la fermeture syntaxique fait toujours peur, il faut sérieusement attacher et travailler sur le Node 101.
chaos
113

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.
   */
}
mjaggard
la source
4
Est-ce un appel à Java?
Ken Sharp
14
C'est Java pas Javascript
RousseauAlexandre
18
@RousseauAlexandre Incorrect. Il s'agit de JavaScript utilisant Rhino (à l'époque, il pourrait également s'agir de Nashorn de nos jours)
mjaggard
71

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 simplement l'utiliser dans une ligne d'appels de fonction comme prévu:

$('#warning')
.addClass('highlight')
.delay(1000)
.removeClass('highlight');
Alan Plum
la source
4
Ce n'est pas une mauvaise solution. Garde le contexte et la chaînabilité.
Nosredna
39
Depuis jQuery 1.4, .delay()fait partie de jQuery (mais avec une sémantique différente de l'implémentation ci-dessus). api.jquery.com/delay
Matt Ball
7
Ce qui manquait définitivement à cette question, c'était une réponse jQuery . Je suis tellement content de l'avoir!
xDaizu
1
Si vous avez besoin d'un délai entre deux appels indépendants, oui. Si vous avez besoin de retards pour ralentir une boucle, non.
WGroleau
46

J'ai également cherché une solution de sommeil (pas pour le code de production, seulement pour les 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/

De plus, lorsque vous appelez alert(), votre code sera également mis en pause, tandis que l'alerte est affichée - vous devez trouver un moyen de ne pas afficher l'alerte mais d'obtenir le même effet. :)

a_w
la source
35
Je suis d'accord, beaucoup de gens disent: "Non, ne fais pas ça dans le code de production!" Ouais, euh, je ne veux pas. Je veux le faire dans du code de test jetable, et en conséquence je ne veux pas passer beaucoup de temps à faire une solution élégante.
user435779
31

Voici une solution simple utilisant un 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 de sleep.php:

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

Maintenant, appelez-le avec: sommeil (5);

pguardiario
la source
5
@lukad, utilisez setTimeout()si cela fonctionne, mais si cela signifie que vous démêlez 1000 lignes de rappels, cela pourrait ne plus ressembler à une blague.
pguardiario
11
Approche unique, mais malheureusement, les requêtes XMLHttpRequests non asynchrones sont obsolètes et seront supprimées à l'avenir. Ce qui est drôle, car c'est ce qui m'a amené à cette question en premier lieu.
Beejor
C'est en fait une assez bonne idée de l'OMI. Bien que je ne pense pas que l'API sleep (URL de demande) devrait être publique car elle peut être utilisée abusivement.
Vahid Amiri
@Beejor penser toujours uniquement à l'avenir signifie vivre d'une irréalité futuriste :-)
user1742529
bien mais savez-vous si parfois Internet est lent ou le temps de ping du site Web est élevé, il dormira le script pendant plus de temps d'argument. Comme si vous utilisez sleep(300)et que le site Web prend 150 ms pour répondre, le code javascript sera en veille pendant 450 ms. et si la connexion Internet est perdue par le navigateur, cela ne fonctionnera que pendant 0 ms. Ce n'est donc pas une meilleure solution
H Chauhan
30

Voici. Comme le dit le code, ne soyez pas un mauvais développeur et utilisez-le sur des sites Web. C'est une fonction utilitaire de développement.

// 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
la source
17
C'est essentiellement la même chose que le PO.
Andrew Barber
5
Pour être plus précis, c'est ce que OP a demandé pour une ALTERNATIVE.
WGroleau
La solution n'est pas bonne, mais à certains endroits, async/awaitelle ne répond malheureusement pas, et nous devons l'utiliser de manière obligatoire.
Nabi KAZ
21

Personnellement, j'aime 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 lors de la création de scripts dans P5js

melMass
la source
3
Je vois cela comme la version la plus optimisée de la question principale: il ne fait aucun calcul à l'intérieur de la boucle, juste une comparaison simple. C'est un peu difficile à lire.
hegez
4
NE JAMAIS FAIRE CELA. Avez-vous vérifié l'utilisation du processeur pendant que cette fonction fonctionne? Il devrait être proche de 100% si vous lui donnez suffisamment de temps.
noego
2
@hegez: Étant donné que la boucle va fonctionner pendant une durée fixe d'horloge murale, quoi qu'il en soit, il semble que l'optimisation de la boucle soit un peu à côté du point.
ShadowRanger
@noego Comment ça? Je viens de tester dans Node 10, je n'ai aucun changement d'utilisation du processeur
melMass
@melMass Cette fonction bloque simplement le thread Node pendant n secondes en gardant le CPU 100% occupé. Cette "solution" est une très mauvaise idée pour ces deux raisons (blocage + tueur de CPU). Attendre DOIT être non bloquant, donc asynchrone.
Jeremy Thille
20

Première:

Définissez une fonction que vous souhaitez exécuter comme ceci:

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

Planifiez ensuite son exécution avec la méthode setTimeout:

setTimeout(alertWorld,1000)

Notez 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
Pablo Fernandez
la source
19

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

assurez-vous que votre fonction d'appel est asynchrone

vérifié et fonctionne bien

Ahmed Mohammedali
la source
1
Finalement. La seule et unique réponse.
Jeremy Thille
18

La meilleure solution pour que les choses ressemblent à 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 le plus proche de quelque chose qui fait simplement ce que vous voulez.

Notez que si vous avez besoin de plusieurs sommeil, cela peut devenir très vite pressé et vous devrez peut-être repenser votre conception.

Mainguy
la source
c'est celui qui a fonctionné pour moi sur les navigateurs de bureau et un ancien téléphone mobile. Les autres que j'ai essayés n'ont pas fonctionné sur tous.
Mike
10

Pour les navigateurs, je conviens que setTimeout et setInterval sont la voie à suivre.

Mais pour le code côté serveur, il peut nécessiter une fonction de blocage (par exemple, afin que vous puissiez effectivement avoir la synchronisation des threads).

Si vous utilisez node.js et meteor, vous pouvez avoir rencontré les limites de l'utilisation de setTimeout dans une fibre. Voici le code de mise en veille côté serveur.

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

Homer6
la source
Server may require a blocking function... Je ne vois pas à quel point bloquer avec force le seul thread de Node et rendre votre serveur entier sans réponse pendant plusieurs secondes est une bonne idée, mais peu importe
Jeremy Thille
10

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 souvenir de la syntaxe si vous utilisiez auparavant Promises.

Elo
la source
4
Pourquoi est-ce mieux que d'utiliser simplement setTimeout (function () {/ * faire quelque chose * /}, 2000) ;?
JSideris
10

Mise à jour 2019 à l'aide d' Atomics.wait

Devrait fonctionner dans le nœud 9.3 ou supérieur.

J'avais besoin d'une minuterie assez précise dans Node.js et cela fonctionne très bien pour cela. Cependant, il semble que le support des navigateurs soit extrêmement limité.

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

A exécuté quelques repères de minuterie de 10 secondes.

Avec setTimeout, j'obtiens une erreur allant jusqu'à 7000 microsecondes. (7 ms)

Avec Atomics, mon erreur semble rester inférieure à 600 microsecondes. (0,6 ms)

Mise à jour 2020: en résumé

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

dont la page côté serveur, par exemple sleep.jsp, ressemble à

<%
try{
  Thread.sleep(Long.parseLong(request.getParameter("millis")));
}catch(InterruptedException e){}
%>
fuweichin
la source
À mon avis, mieux que la solution acceptée qui ne peut pas être implémentée comme une simple fonction sans async / wait dans l'appelant.
GroovyDotCom
oui, tant que vous savez que cela bloque et que ce n'est généralement pas une bonne chose
Kapytanhook
Assez cool, mais le fait que cela ne soit vraiment pris en charge que dans Chrome et Firefox ne le rend pas très viable pour les utilisations sur le Web. (Nov 2019)
JGreatorex
9

La plupart des réponses ici sont erronées ou pour le moins dépassées. Il n'y a aucune raison que le javascript doive être monothread, et ce n'est pas le cas. Aujourd'hui, tous les navigateurs traditionnels prennent en charge les travailleurs, avant que ce ne soit le cas d'autres runtimes javascript comme Rhino et Node.js prennent en charge le multithreading.

'Javascript is single threaded' n'est pas une réponse valide. Par exemple, l'exécution d'une fonction de veille au sein d'un travailleur ne bloquerait aucun du code exécuté dans le thread d'interface utilisateur.

Dans les runtimes plus récents prenant en charge les générateurs et le rendement, on pourrait apporter des fonctionnalités similaires à la fonction de veille dans un environnement à thread unique:

// 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 thread. C'est simplement du sucre en plus de la fonction setTimeout actuelle de javascript. Ce type de fonctionnalité a été implémenté dans Task.js et devrait fonctionner aujourd'hui dans Firefox.

Gabriel Ratener
la source
Les travailleurs ne sont pas implémentés dans IE, au moins jusqu'à la version 10. Ce qui représente actuellement un grand nombre d'utilisateurs.
Beejor
Certes, et même alors, il n'est pas pratique de l'implémenter en sleeputilisant plusieurs travailleurs. Si vous utilisez les fonctions du générateur Node.js, elles sont déjà implémentées et peuvent être utilisées comme décrit. Les navigateurs traditionnels n'ont pas tous implémenté de générateurs à ce jour.
Gabriel Ratener
8

J'ai recherché / googlé pas mal de pages Web sur le sommeil / l'attente de Javascript… et il n'y a PAS de réponse si vous voulez que Javascript soit à "RUN, DELAY, RUN" ... ce que la plupart des gens ont obtenu était "RUN, RUN (inutile ) "RUN" ou "RUN, RUN + RUN retardé" ....

J'ai donc mangé des hamburgers et j'ai réfléchi ::: voici une solution qui fonctionne ... mais vous devez couper vos codes de fonctionnement ... ::: oui, je sais, c'est juste un refactoring plus facile à lire .. . encore...

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

// .................................... // 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>
user207408
la source
5
Ok, cela fonctionne avec setTimeput, mais il est difficile de voir ce qui se passe. Utiliser setTimeout lui-même est plus simple que cela.
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
la source
C'est la même chose que la vraie question. Pas grand-chose en faisant la vraie réponse.
EML
2
Ce n'est pas une bonne solution - l'utiliser dans JavaScriptExecutor de Selenium bloque mon navigateur Chrome environ 50% du temps sur un MacBook Pro 2104.
emery
7

La solution la plus courte sans dépendances:

await new Promise(resolve => setTimeout(resolve, 5000));
k06a
la source
Cela ne fonctionne pas dans IE11. Nous obtenons une erreur de syntaxe pour la fonction flèche.
DDphp
@ Utilisation Java-DKawait new Promise(function(resolve) { setTimeout(resolve, 5000); });
k06a
6

Vous ne pouvez pas faire un sommeil comme ça en JavaScript, ou, plutôt, vous ne devriez pas. L'exécution d'une veille ou d'une boucle while entraîne le blocage 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 référencé.

Andrew Dunkman
la source
6

Un scénario où vous voudrez peut-être 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 contextuelle, et que vous avez initié un traitement qui nécessite une courte période pour terminer avant que la fenêtre contextuelle ne s'affiche. Déplacer la fenêtre ouverte dans une fermeture signifie qu'elle est généralement bloquée par le navigateur.

acuth
la source
6

Je peux comprendre le but d'une fonction de veille si vous devez gérer une exécution synchrone. Les fonctions setInterval et setTimeout 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 des événements et des gestionnaires, mais dans certains cas, ce n'est pas ce qui est prévu.

naazgull
la source
6

Ajout de mes deux bits. J'avais besoin d'une attente occupée à des fins de test. Je ne voulais pas diviser 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 à faire cela et cela a fait l'affaire pour moi.

caiocpricci2
la source
Cela pourrait être compilé.
Viktor Sehr
Veuillez ne pas le faire de cette façon. Il s'agit d'un appel de veille bloquant , ce qui signifie qu'aucun autre javascript ne peut s'exécuter pendant que votre code monopolise le thread JS.
Steve Midgley
5
@SteveMidgley "aucun autre javascript [ne pouvant] s'exécuter pendant que votre code monopolise le thread JS" me semble être exactement ce que l'OP veut faire ¯_ (ツ) _ / ¯
drigoangelo
1
Je viens de lancer quelques tests et il semble que même une boucle vide bloquera le navigateur et le CPU (pas seulement JavaScript). Et l'utilisation de forboucles s'exécutera presque toujours immédiatement, quelle que soit la valeur maximale de i, et même avec du code mathématique complexe placé à l'intérieur. Donc, à moins que vous n'attendiez que quelques millisecondes, il ne semble toujours pas possible de dormir gracieusement dans JS.
Beejor
1 million, c'est trop gros. Pour moi, assez 10k
Vlad
6

Cela peut être fait en utilisant la méthode de sommeil de Java. Je l'ai testé dans FF et IE et il ne verrouille pas l'ordinateur, ne mâche pas les ressources ou ne provoque pas de coups de serveur sans fin. Cela me semble une solution propre.

Vous devez d'abord charger Java sur la page et rendre ses méthodes disponibles. Pour ce faire, je l'ai fait:

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

Ensuite, tout ce que vous avez à faire lorsque vous souhaitez 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 back-end dans une très petite entreprise et je devais imprimer une facture qui devait être chargée depuis le serveur. Je l'ai fait en chargeant la facture (en tant que page Web) dans un iFrame puis en imprimant l'iFrame. Bien sûr, j'ai dû attendre que la page soit entièrement chargée avant de pouvoir imprimer, le JS a donc dû s'arrêter. J'ai accompli cela en ayant la page de facture (dans l'iFrame) changer un champ de formulaire caché sur la page parent avec l'événement onLoad. Et le code sur la page parent 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 le chargement de la page de facture, puis ouvre la boîte de dialogue d'impression pour que l'utilisateur l'envoie à l'imprimante. QED.

Rachael
la source
12
Semble une soulution assez monstrueuse quand on considère la chose simple que l'auteur voulait réaliser.
xaralis
2
Cela dépend des applets Java qui sont obsolètes.
Vahid Amiri
6

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 des fonctions moins maladroites que setTimeoutet setInterval, vous pouvez les encapsuler dans des fonctions qui inversent simplement l'ordre des arguments et leur donnent de beaux noms:

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

Versions de CoffeeScript:

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

Vous pouvez ensuite les utiliser correctement avec des 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, ...")

1j01
la source
5

Pour le cas spécifique de vouloir espacer un ensemble d'appels en cours d'exécution par une boucle, vous pouvez utiliser quelque chose comme le code ci-dessous avec prototype. Sans prototype, vous pouvez remplacer la fonction de retard 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)
}
beauburrier
la source
5

Si vous êtes sur node.js, vous pouvez voir les fibres - une extension C native vers node, une simulation un peu multi-threading.

Il vous permet de faire un réel sleepd'une manière qui bloque l'exécution dans une fibre, mais il n'est pas bloquant dans le thread principal et d'autres fibres.

Voici un exemple fraîchement extrait de leur propre fichier Lisez-moi:

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

- 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)
tomekwi
la source