web-dev-qa-db-fra.com

Veille en JavaScript - délai entre les actions

Existe-t-il un moyen de dormir en JavaScript avant qu'il ne réalise une autre action?

Exemple:

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

Vous pouvez utiliser setTimeout pour obtenir un effet similaire:

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

Cela ne "met" pas vraiment le JavaScript en veille - il exécute simplement la fonction passée à setTimeout aprè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 d'utiliser setTimeout si possible car cela ne gèle pas tout pendant la période de veille.

122
Steve Harrison

Au cas où vous auriez vraiment besoin d’un sleep() pour tester quelque chose. Mais sachez que cela bloquera le navigateur la plupart du temps lors du 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 perdre de la mémoire, de la puissance de traitement, de la batterie et éventuellement la durée de vie de votre appareil.

39
Rodrigo

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

Comme la question initiale avait été postée il y a sept ans, je n'ai pas pris la peine de répondre avec le code exact, car c'était trop facile et déjà répondu. Cela devrait aider à résoudre des problèmes plus complexes, par exemple si vous avez besoin d'au moins deux mises en veille ou si vous envisagez de séquencer une exécution asynchrone. N'hésitez pas à le modifier pour l'adapter à 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()

une fonction*

() => fonction de 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 beaucoup plus simple et moins sophistiqué 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 n'attendez qu'une condition, vous pouvez attendre comme ceci

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
)

9
Íhor Mé

Mise à jour 2018

Les dernières versions de Safari, Firefox et Node.js, prennent également en charge async/wait/promises.

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 nouvel async/wait/Promise est en cours de déploiement. Vous trouverez ci-dessous deux solutions, une avec une fonction de générateur qui fonctionnera sur tous les navigateurs modernes, et une autre, utilisant le nouvel async/wait qui n’est pas encore prise en charge partout.

Utiliser une fonction génératrice:

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

Utiliser async/wait/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();

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 diffère de Quelle est la version JavaScript de sleep ()? où le demandeur demande un sommeil réel (pas d'autre exécution de code sur le processus) plutôt qu'un délai entre les actions.

7
niry

Si vous voulez des fonctions moins encombrantes que setTimeout et setInterval, vous pouvez les envelopper dans des fonctions qui inversent simplement l'ordre des arguments et leur attribuez de jolis noms:

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

Versions 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, ...")

3
1j01

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;

}
2
Noelmout

Essayez cette fonction:

function delay(ms, cb) { setTimeout(cb, ms) }

Si vous utilisez Babel:

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

Voici un demo .

0
Richie Bendall

Ceci est mon modèle qui montre comment "dormir" ou "DoEvents" en javascript en utilisant une fonction de générateur (ES6). Code commenté:

<html>
<head>
<script>
  "use strict"; // always
  // Based on post by www-0av-Com https://stackoverflow.com/questions/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>
0
dcromley

Il y a plusieurs façons de résoudre ce problème. Si nous utilisons la fonction setTimeout, commençons par la connaître . Cette fonction a trois paramètres: function ou code, delay (en millisecondes) et le parameters . Étant donné que le paramètre function ou code est requis, les autres sont facultatifs . Une fois que vous n'avez pas entré le delay, il sera défini à zéro.

Pour plus de détails sur la setTimeout()allez à 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 -> Identifiant numérique de la liste des timeouts actifs 
b = 8


En utilisant le paramètre pass:

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 -> Identifiant numérique de la liste des délais d'attente actifs 
b = 8



Support du navigateur:

 Chrome Firefox Edge Safari Opera 
 1.0 1.0 4.0 1.0 4.0 
0

Voici un moyen très simple de le faire qui "ressemble" à une veille/pause synchrone, mais qui est un code async 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');
}
0
user2330237