Sleep in JavaScript - délai entre les actions

129

Existe-t-il un moyen de faire une veille en JavaScript avant d'effectuer une autre action?

Exemple:

 var a = 1+3;
 // Sleep 3 seconds before the next action here
 var b = a + 4;
Jin Yong
la source

Réponses:

140

Vous pouvez utiliser setTimeoutpour obtenir un effet similaire:

var a = 1 + 3;
var b;
setTimeout(function() {
    b = a + 4;
}, (3 * 1000));

Cela ne «dort» pas vraiment JavaScript - il exécute simplement la fonction passée setTimeoutaprès une certaine durée (spécifiée en millisecondes). Bien qu'il soit possible d'écrire une fonction de veille pour JavaScript, il est préférable de l'utiliser setTimeoutsi possible car elle ne gèle pas tout pendant la période de sommeil.

Steve Harrison
la source
9
Jetez également un œil à setInterval (). C'est similaire à setTimeout (), mais votre fonction est appelée plusieurs fois (jusqu'à ce que vous l'arrêtiez), ce qui est utile si vous voulez faire quelque chose en dormant (comme faire des mises à jour de progression, conserver un état interne, ou autre).
Anders Sandvig
5
Cela ne répond pas à la question. La question demande un équivalent «sommeil», ce qui n'est pas le cas.
felwithe le
Bien que cette réponse ne corresponde pas à la question posée, elle est plus utile que la boucle et comparer Date.now (). Personne de quoi utiliser une boucle bloquée le sommeil de l'outil.
Li Chunlin
2
À moins, bien sûr, qu'une boucle de blocage soit exactement ce que quelqu'un veut.
Wonko the Sane
55

Au cas où vous auriez vraiment besoin sleep()de tester quelque chose. Mais sachez qu'il plantera le navigateur la plupart du temps pendant le débogage - c'est probablement pourquoi vous en avez besoin de toute façon. En mode production, je commenterai cette fonction.

function pauseBrowser(millis) {
    var date = Date.now();
    var curDate = null;
    do {
        curDate = Date.now();
    } while (curDate-date < millis);
}

N'utilisez pas new Date()dans la boucle, sauf si vous souhaitez gaspiller de la mémoire, de la puissance de traitement, de la batterie et éventuellement la durée de vie de votre appareil.

Rodrigo
la source
8
Cette réponse mérite plus de votes. En vedette la question juste cause de cette réponse.
jagc
qu'en est-il de l'avertissement "trop ​​de récursivité"?
Oki Erie Rinaldi
1
@OkiErieRinaldi Il n'y a pas de récursion ici, c'est seulement une boucle.
Rodrigo
7
@ 3.1415926535897932384626433833 Eh bien, quelqu'un a demandé une fonction "sommeil", c'est ce qu'il y a ici. Je l'ai utilisé une fois, je ne me souviens pas exactement pour quel type de débogage. Si j'en ai encore besoin, je sais exactement où le trouver. Si vous préférez une autre fonction, c'est votre choix. N'est-ce pas formidable de pouvoir choisir?
Rodrigo
2
"Attente occupée".
Zeek2
13

Version ECMAScript 6, utilisant des générateurs avec rendement pour "blocage de code":

Parce que la question originale a été postée il y a sept ans, je n'ai pas pris la peine de répondre avec le code exact, car c'est trop facile et déjà répondu. Cela devrait vous aider dans des problèmes plus compliqués, comme si vous avez besoin d'au moins deux sommeil, ou si vous prévoyez de séquencer une exécution asynchrone. N'hésitez pas à le modifier en fonction de vos besoins.

let sleeptime = 100
function* clock()
{
    let i = 0
    while( i <= 10000 )
    {
        i++
        console.log(i); // actually, just do stuff you wanna do.
        setTimeout(
            ()=>
            {
                clk.next()
            }
            , sleeptime
        )
        yield
    }
}

let clk = clock()
clk.next()

fonction*

() => fonction flèche

Vous pouvez également enchaîner des événements via Promises :

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


sleep(1000).then(function()
{
    console.log('1')
    sleep(1000).then(function()
    {
        console.log('2')
    })
})

Ou une manière beaucoup plus simple et moins sophistiquée serait

function sleep(ms, f)
{
    return(
        setTimeout(f, ms)
    )
}


sleep(500, function()
{
    console.log('1')
    sleep(500, function()
    {
        console.log('2')
    })
})
console.log('Event chain launched')

Si vous attendez juste qu'une condition se produise, vous pouvez attendre comme ça

function waitTill(condition, thenDo)
{
    if (eval(condition))
    {
        thenDo()
        return
    }

    setTimeout(
        ()    =>
        {
            waitTill(condition, thenDo)
        }
        ,
        1
    )
}

x=0

waitTill(
    'x>2 || x==1'
    ,
    ()    =>
    {
        console.log("Conditions met!")
    }
)

// Simulating the change
setTimeout(
    () =>
    {
        x = 1
    }
    ,
    1000
)

Íhor Mé
la source
11

Mise à jour 2018

Les derniers Safari, Firefox et Node.js prennent désormais également en charge async / await / promises.

Utilisation de async / await / Promises:

(À partir de 1/2017, pris en charge sur Chrome, mais pas sur Safari, Internet Explorer, Firefox, Node.js)

'use strict';

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

let myAsyncFunc = async function() {
  console.log('Sleeping');
  await sleep(3000);
  console.log('Done');
}

myAsyncFunc();

Mise à jour 2017

JavaScript a évolué depuis que cette question a été posée et a maintenant des fonctions de générateur, et le nouveau async / await / Promise est en cours de déploiement. Ci-dessous, il y a deux solutions, une avec une fonction de générateur qui fonctionnera sur tous les navigateurs modernes, et une autre, utilisant le nouveau async / await qui n'est pas encore pris en charge partout.

Utilisation d'une fonction générateur:

'use strict';

let myAsync = (g) => (...args) => {
    let f, res = () => f.next(),
        sleep = (ms) => setTimeout(res, ms);
    f = g.apply({sleep}, args); f.next();
};

let myAsyncFunc = myAsync(function*() {
    let {sleep} = this;
    console.log("Sleeping");
    yield sleep(3000);
    console.log("Done");
});

myAsyncFunc();

Faites attention au fait que ces deux solutions sont de nature asynchrone. Cela signifie que myAsyncFunc (dans les deux cas) reviendra pendant le sommeil.

Il est important de noter que cette question est différente de Quelle est la version JavaScript de sleep ()? où le demandeur demande un vrai sommeil (aucune autre exécution de code sur le processus) plutôt qu'un délai entre les actions.

niry
la source
1
Meilleure réponse à ce jour !! J'ai passé 30 minutes à chercher partout pour trouver ça .. grand merci !!!
538ROMEO
1
J'ai raté cette réponse en cherchant une solution et j'ai réinventé le vélo: D Si seulement je le voyais avant cela me ferait gagner des heures !! Vote positif!
sserzant le
let co = gen => (...args) => { let iter = gen(...args); let resume = () => new Promise((resolve, reject) => { let result = iter.next(); if (result.done) resolve(result.value); else Promise.resolve(result.value).then(resume).then(resolve, reject); }); return resume(); };vous permettrait d' let asyncAdd = co(function* (a, b) { console.log('Sleeping'); yield sleep(3000); console.log('Done'); return a + b; }); asyncAdd(3, 4).then(console.log);utiliser la définition de à sleep()partir de votre deuxième bloc de code.
Patrick Roberts le
3

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 jolis 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 joliment 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
2

Une autre façon de le faire est d'utiliser Promise et setTimeout (notez que vous devez être à l'intérieur d'une fonction et la définir comme asynchrone avec le mot clé async):

async yourAsynchronousFunction () {

    var a = 1+3;

    await new Promise( (resolve) => {
        setTimeout( () => { resolve(); }, 3000);
    }

    var b = a + 4;

}
Ostn
la source
2

Voici un moyen très simple de le faire qui «ressemble» à un sommeil / pause synchrone, mais qui est un code async js légitime.

// Create a simple pause function
const pause = (timeoutMsec) => new Promise(resolve => setTimeout(resolve,timeoutMsec))

async function main () {
    console.log('starting');
    // Call with await to pause.  Note that the main function is declared asyc
    await pause(3*1000)
    console.log('done');
}

utilisateur2330237
la source
1

Vous pouvez utiliser du javascript simple, cela appellera votre fonction / méthode après 5 secondes:

setTimeout(()=> { your_function(); }, 5000);
Le cheval noir
la source
0

Il existe plusieurs façons de résoudre ce problème. Si nous utilisons la setTimeoutfonction, apprenons à la connaître en premier. Cette fonction a trois paramètres: functionou code, delay(en millisecondes) et le parameters. Le paramètre de fonction ou de code étant obligatoire, les autres sont facultatifs. Une fois que vous n'avez pas saisi le délai , il sera remis à zéro.

Pour plus de détails sur le, setTimeout() allez sur ce lien .

Version simplifiée:

var a = 1 + 3;
var b;
console.log('a = ' + a);
setTimeout(function(){ 
    b = a + 4; 
    console.log('b = ' + b);
}, 1000);

sortie:
a = 4
24 -> Numéro identifiant de la liste des timeouts actifs
b = 8


Utilisation de la passe de paramètres:

var a = 1 + 3;
var b;
console.log('a = ' + a);
setTimeout(myFunction, 1000, a);

function myFunction(a)
{
    var b = a + 4;
    console.log('b = ' + b);
}

sortie:
a = 4
25 -> Numéro identifiant de la liste des timeouts actifs
b = 8



Prise en charge du navigateur:

Chrome Firefox Edge Safari Opera
1,0 1,0 4,0 1,0 4,0
Alexandre Neukirchen
la source
0

C'est mon modèle qui montre comment "dormir" ou "DoEvents" en javascript à l'aide d'une fonction générateur (ES6). Code commenté:

<html>
<head>
<script>
  "use strict"; // always
  // Based on post by www-0av-Com /programming/3143928
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*
  var divelt, time0, globaln = 0; // global variables
  var MainGenObj = Main(); // generator object = generator function()
window.onload = function() {
  divelt = document.getElementsByTagName("body")[0]; // for addline()
  addline("typeof Main: " + typeof Main);
  addline("typeof MainDriver: " + typeof MainDriver);
  addline("typeof MainGenObj: " + typeof MainGenObj);
  time0 = new Date().valueOf(); // starting time ms
  MainDriver(); // do all parts of Main()
}
function* Main() { // this is "Main" -- generator function -- code goes here
  // could be loops, or inline, like this:

  addline("Part A, time: " + time() + ", " + ++globaln); // part A
  yield 2000;                    // yield for 2000 ms (like sleep)

  addline("Part B, time: " + time() + ", " +  ++globaln); // part B
  yield 3000;                    // yield for 3000 ms (or like DoEvents)

  addline("Part Z, time: " + time() + ", " +  ++globaln); // part Z (last part)
  addline("End, time: " + time());
}
function MainDriver() { // this does all parts, with delays
  var obj = MainGenObj.next(); // executes the next (or first) part of Main()
  if (obj.done == false) { // if "yield"ed, this will be false
    setTimeout(MainDriver, obj.value); // repeat after delay
  }
}
function time() { // seconds from time0 to 3 decimal places
  var ret = ((new Date().valueOf() - time0)/1000).toString();
  if (ret.indexOf(".") == -1) ret += ".000";
  while (ret.indexOf(".") >= ret.length-3) ret += "0";
  return ret;
}
function addline(what) { // output
  divelt.innerHTML += "<br />\n" + what;
}
</script>
</head>
<body>
<button onclick="alert('I\'m alive!');"> Hit me to see if I'm alive </button>
</body>
</html>
Dcromley
la source
0

Essayez cette fonction:

const delay = (ms, cb) => setTimeout(cb, ms)

Voici comment vous l'utilisez:

console.log("Waiting for 5 seconds.")
delay(5000, function() {
  console.log("Finished waiting for 5 seconds.")
})

Ou allez-y avec style:

const delay = ms => new Promise(resolve => {
    setTimeout(resolve, ms)
})

Voici une démo .

Richie Bendall
la source