Sospensione in JavaScript: ritardo tra le azioni


129

C'è un modo in cui posso dormire in JavaScript prima che esegua un'altra azione?

Esempio:

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

Risposte:


140

Puoi usare setTimeoutper ottenere un effetto simile:

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

Questo in realtà non "sospende" JavaScript: esegue solo la funzione passata setTimeoutdopo una certa durata (specificata in millisecondi). Sebbene sia possibile scrivere una funzione di sospensione per JavaScript, è consigliabile utilizzarla setTimeoutse possibile in quanto non congela tutto durante il periodo di sospensione.


9
Dai un'occhiata anche a setInterval (). È simile a setTimeout (), ma la tua funzione viene chiamata più volte (fino a quando non la interrompi), che è utile se vuoi fare qualcosa mentre dormi (come fare aggiornamenti sui progressi, mantenere uno stato interno o altro).
Anders Sandvig,

5
Questo non risponde alla domanda. La domanda richiede un equivalente "sonno" che non è questo.
felwithe

Sebbene questa risposta non corrisponda a ciò che la domanda è stata posta, ma è più utile del ciclo e confronta Date.now (). Nessuno cosa usare un loop bloccato l'attrezzo sleep.
Li Chunlin,

2
A meno che, naturalmente, un loop di blocco sia esattamente ciò che qualcuno vuole.
Wonko the Sane,

55

Nel caso in cui tu abbia davvero bisogno di un sleep()solo per testare qualcosa. Ma tieni presente che si bloccherà il browser la maggior parte delle volte mentre debuggin - probabilmente è per questo che ti serve comunque. In modalità produzione commenterò questa funzione.

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

Non utilizzare new Date()in loop, a meno che non si desideri sprecare memoria, potenza di elaborazione, batteria e possibilmente la durata del dispositivo.


8
Questa risposta merita più voti. Protagonista la domanda proprio per questa risposta.
Jagc

che dire dell'avvertimento "troppa ricorsione"?
Oki Erie Rinaldi,

1
@OkiErieRinaldi Non c'è ricorsione lì, è solo un ciclo.
Rodrigo,

7
@ 3.1415926535897932384626433833 Beh, qualcuno ha chiesto una funzione "sleep", ecco cosa c'è. L'ho usato una volta, non ricordo esattamente per quale tipo di debug. Se mai ne avrò più bisogno, so esattamente dove trovarlo. Se preferisci un'altra funzione, questa è la tua scelta. Non è bello poter scegliere?
Rodrigo,

2
"Occupato in attesa".
Zeek2,

13

Versione ECMAScript 6, utilizzando generatori con rendimento per "blocco del codice":

Poiché la domanda originale è stata pubblicata sette anni fa, non mi sono preoccupato di rispondere con il codice esatto, perché è semplicemente troppo facile e già risposto. Questo dovrebbe aiutare in problemi più complicati, come se hai bisogno di almeno due dormienti o se stai pianificando una sequenza di esecuzione asincrona. Sentiti libero di modificarlo per adattarlo alle tue esigenze.

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

funzione*

() => funzione freccia

Puoi anche concatenare eventi tramite 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')
    })
})

O sarebbe molto più semplice e meno sofisticato

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

Se stai solo aspettando che si verifichino delle condizioni, puoi aspettare così

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
)


11

Aggiornamento 2018

Gli ultimi Safari, Firefox e Node.js ora supportano anche async / waitit / promesse.

Utilizzando async / await / Promises:

(A partire dal 1/2017, supportato su Chrome, ma non su 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();

Aggiornamento 2017

JavaScript si è evoluto da quando questa domanda è stata posta e ora ha funzioni di generatore e il nuovo asincrono / attende / Promessa è in fase di implementazione. Di seguito ci sono due soluzioni, una con la funzione generatore che funzionerà su tutti i browser moderni e un'altra, usando il nuovo asincrono / wait che non è ancora supportato ovunque.

Utilizzando una funzione del generatore:

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

Prestare attenzione al fatto che entrambe queste soluzioni sono di natura asincrona. Ciò significa che myAsyncFunc (in entrambi i casi) tornerà durante il sonno.

È importante notare che questa domanda è diversa da Qual è la versione JavaScript di sleep ()? dove il richiedente richiede il vero sonno (nessun'altra esecuzione di codice sul processo) piuttosto che un ritardo tra le azioni.


1
La migliore risposta finora !! Ho passato 30 minuti a cercare dappertutto per trovarlo .. grande grazie !!!
538ROMEO,

1
Ho perso questa risposta mentre cercavo una soluzione e ho reinventato la bicicletta: D Se solo la vedessi prima mi risparmierebbe ore !! Upvoted!
sabato

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(); };ti lascerebbe fare let asyncAdd = co(function* (a, b) { console.log('Sleeping'); yield sleep(3000); console.log('Done'); return a + b; }); asyncAdd(3, 4).then(console.log);usando la definizione di sleep()dal tuo secondo blocco di codice.
Patrick Roberts,

3

Se vuoi funzioni meno ingombranti di setTimeoute setInterval, puoi avvolgerle in funzioni che invertono semplicemente l'ordine degli argomenti e danno loro dei bei nomi:

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

Versioni di CoffeeScript:

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

Puoi quindi usarli bene con funzioni anonime:

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

Ora si legge facilmente come "dopo N millisecondi, ..." (o "ogni N millisecondi, ...")


2

Un altro modo per farlo è usare Promise e setTimeout (nota che devi essere all'interno di una funzione e impostarlo come asincrono con la parola chiave asincrona):

async yourAsynchronousFunction () {

    var a = 1+3;

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

    var b = a + 4;

}

2

Ecco un modo molto semplice per farlo che "sembra" un sonno / pausa sincrono, ma è un codice asincrono js legittimo.

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


1

Puoi usare javascript semplice, questo chiamerà la tua funzione / metodo dopo 5 secondi:

setTimeout(()=> { your_function(); }, 5000);

0

Esistono diversi modi per risolvere questo problema. Se utilizziamo la setTimeoutfunzione, scopriamola prima. Questa funzione ha tre parametri: functiono code, delay(in millisecondi) e il parameters. Poiché è richiesta la funzione o il parametro del codice , gli altri sono opzionali. Dopo aver inserito il ritardo , verrà impostato su zero.

Per maggiori dettagli su setTimeout() vai a questo link .

Versione semplificata:

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

output:
a = 4
24 -> Identificatore numero dell'elenco di timeout attivi
b = 8


Utilizzando il parametro 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);
}

output:
a = 4
25 -> Identificatore numerico dell'elenco dei timeout attivi
b = 8



Supporto browser:

Chrome Firefox Edge Safari Opera
1.0 1.0 4.0 1.0 4.0

0

Questo è il mio modello che mostra come "dormire" o "DoEvents" in javascript usando una funzione di generatore (ES6). Codice commentato:

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

0

Prova questa funzione:

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

Ecco come lo usi:

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

O prometti stile:

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

Ecco una demo .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.