Qual é a versão JavaScript do sleep ()?

2335

Existe uma maneira melhor de projetar um sleepem JavaScript do que a seguinte pausecompfunção ( extraída daqui )?

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

Esta não é uma duplicata do sono em JavaScript - atraso entre ações ; Eu quero um sono real no meio de uma função, e não um atraso antes que um pedaço de código seja executado.

fmsf
fonte
4
É a set no meio de um tempo, se eu usar setTimeout o tempo vai continuar a processo e fila mais setTimeouts o que acabará por ser em execução ao mesmo tempo e fazendo um pouco de concorrência entre si
FMSF
160
Essa é uma solução horrível - você estará mastigando os ciclos de processamento sem fazer nada.
17 de 26
12
O único objetivo de uma suspensão é pesquisar ou aguardar um retorno de chamada - setInterval e setTimeout se saem melhor que isso.
Annakata 04/06/09
1
Provavelmente, você pode fazer o que quiser com o estilo de passagem contínua em JavaScript. Dê uma olhada neste artigo.
Ognyan Dimitrov

Respostas:

2563

Atualização 2017 - 2019

Desde 2009, quando essa pergunta foi feita, o JavaScript evoluiu significativamente. Todas as outras respostas agora estão obsoletas ou excessivamente complicadas. Aqui está a melhor prática atual:

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

É isso. await sleep(<duration>).

Ou como uma linha:

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

Observe que,

  1. awaitsó pode ser executado em funções prefixadas com a asyncpalavra - chave ou no nível superior do seu script em alguns ambientes (por exemplo, o console do Chrome DevTools ou o Runkit).
  2. awaitpausa apenas a asyncfunção atual

Dois novos recursos de JavaScript ajudaram a escrever essa função "sleep":

Compatibilidade

Se por algum motivo estranho você estiver usando Node mais velho do que 7 (que chegou a final da vida ), ou são alvo navegadores antigos, async/ awaitainda pode ser utilizada através de Babel (uma ferramenta que irá transpile JavaScript + novas funcionalidades em bom e velho JavaScript) , com o transform-async-to-generatorplugin.

Dan Dascalescu
fonte
5
Ótimas coisas aqui. Eu me pergunto, como isso afeta ou se relaciona com os estados "ativos" / "inativos" dos navegadores modernos depois que JS chama o modo "inativo"? O navegador pode bloquear o sono conforme o esperado para o JS geral, para recuperar mais tarde quando se tornar "ativo" ou tiver um comportamento diferente?
Andre Canilho 12/10
18
Qual é o suporte atual do navegador para isso? Eu não consideraria as soluções anteriores "obsoletas" até que essa solução seja suportada pela grande maioria dos navegadores, ou pelo menos por todos os comuns. Pelo contrário, consideraria esta solução interessante, mas inutilizável / impraticável até que tenha amplo apoio.
Alvin Thompson
75
Isso não é "sono real" e não responde à pergunta. A pessoa que perguntou fez uma distinção clara entre stackoverflow.com/questions/758688/sleep-in-javascript e sua pergunta. No sono real, nenhum outro código pode ser executado (a menos que em outro encadeamento). Essa resposta é boa para a outra pergunta.
niry 11/01
4
@jacroe - as alças transpiler arrow funções, bem como async / await (o que causaria IE ao sangue vômito de qualquer maneira)
Jaromanda X
11
O JavaScript @niry, sendo uma linguagem de thread único, não é adequado para suspensão "real", pois é executado no mesmo thread da interface do usuário e pode causar páginas da web que não respondem.
Patrick Roberts
849

(Veja a resposta atualizada para 2016 )

Eu acho perfeitamente razoável querer executar uma ação, esperar e depois executar outra ação. Se você está acostumado a escrever em idiomas multithread, provavelmente terá a idéia de executar a execução por um período de tempo definido até que o thread seja ativado.

O problema aqui é que o JavaScript é um modelo baseado em evento de thread único. Enquanto, em um caso específico, pode ser bom esperar o mecanismo inteiro por alguns segundos; em geral, é uma prática ruim. Suponha que eu quisesse usar suas funções enquanto escrevia minhas próprias? Quando chamei seu método, meus métodos congelariam. Se o JavaScript puder, de alguma forma, preservar o contexto de execução da sua função, armazene-o em algum lugar, traga-o de volta e continue mais tarde, então o sono pode acontecer, mas isso seria basicamente o encadeamento.

Portanto, você está praticamente preso ao que os outros sugeriram - precisará dividir seu código em várias funções.

Sua pergunta é um pouco de uma escolha falsa, então. Não há como dormir da maneira que você deseja, nem deve buscar a solução sugerida.

Ben Flynn
fonte
45
Esta não é uma resposta correta. Se o Javascript não tiver uma função de suspensão, é apenas porque o ECMAScript não a exige. É uma escolha de design pelo organismo responsável pelo design de Javascript. Poderia ter sido feito que o tempo de execução do Javascript espera um determinado período de tempo antes de executar a próxima linha de código, mas foi escolhido para não.
Didier A.
5
Um sono pode ser perfeitamente implementado em JavaScript, embora não com precisão em tempo real. Afinal, é um sistema baseado em eventos. Se as chamadas assíncronas forem concluídas, um evento será acionado. Não vejo razão para que o mesmo não seja possível quando um sono () é emitido, após o qual o controle é retornado ao navegador até o sono terminar, retornando o controle à função de chamada. E sim, eu também concordo que às vezes dormir é útil especialmente quando os desenvolvedores ANTES você errou o design tão mal que você não tem outra saída além completamente refatoração para o qual você não tem tempo
Lawrence
Tente hipnótica, que segue esta ideia: coolwanglu.github.io/hypnotic/web/demo.html
Tezcat
4
Chamar javascript single-threaded é apenas um mito. Embora possa ser tecnicamente correto, funcionalmente atua como um idioma multithread. Simular um fork () é trivialmente fácil e, embora o yield () não seja realmente implementável, você pode se aproximar bastante usando a memória compartilhada para bloquear / semáforo. Para o programador médio, faz sentido tratá-lo como multiencadeado; o nome técnico é importante apenas para os desenvolvedores do idioma.
Benubird 29/01
8
Concordo por que sleep()não é possível em JS e que na maioria das vezes existem maneiras melhores de fazer as coisas. Mas eu ainda consideraria a maneira como o mecanismo vincula todas as coisas como uma falha de design; não há razão para que o idioma não possa ter uma sleep()função limitada a um script, página ou função específica sem que o mecanismo atrapalhe a CPU e congele o aplicativo como um maníaco. É 2015 e você não deve conseguir travar um navegador da web inteiro while(1). Temos Flash para coisas assim.
Beejor 12/09/15
660

Em JavaScript, reescrevo todas as funções para que possam terminar o mais rápido possível. Você deseja que o navegador volte ao controle para que ele possa fazer alterações no seu DOM.

Toda vez que eu queria dormir no meio da minha função, eu refatorava para usar a setTimeout().

Editar

O sono infame, ou atraso, função em qualquer idioma é muito debatido. Alguns dirão que sempre deve haver um sinal ou retorno de chamada para disparar uma determinada funcionalidade, outros argumentarão que às vezes um momento arbitrário de atraso é útil. Eu digo que cada uma delas e uma regra nunca podem ditar nada neste setor.

Escrever uma função de suspensão é simples e ainda mais utilizável com o 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
fonte
190
A título de encerramento. function foobar(el) { setTimeout(function() { foobar_cont(el); }, 5000); }
caos
68
ok, e se o código não se destinar a ser usado em uma página da web?
Eugenio Miró
10
@ EugenioMiró Se o código não se destina a ser utilizado em uma página da Web, faça com que o modelo de objeto do host implemente um método sleep. - Eu acho que a pergunta é voltada para o DOM, que é exposto ao javascript em execução nas páginas da web.
precisa saber é o seguinte
31
@Nosredna sim, entendemos como fazer chamadas assíncronas, isso não nos ajuda a dormir (). Quero que minhas chamadas sejam feitas em uma determinada ordem e que os dados sejam devolvidos em uma determinada ordem. Eu tenho 5 níveis de profundidade em um loop for. Eu quero bloquear a execução. Um método de suspensão real não "desacelera o navegador", o controle das mãos de suspensão volta ao navegador e a quaisquer outros segmentos que desejam tempo de CPU enquanto ele ainda está bloqueando.
precisa saber é o seguinte
382
isso não é uma resposta para a pergunta.
TMS
303

Somente para debug / dev , eu posto isso se for útil para alguém

Coisas interessantes, no Firebug (e provavelmente em outros consoles js), nada acontece depois de pressionar enter, somente após a duração do sono especificada (...)

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

Exemplo de uso:

function sleepThenAct(){ sleepFor(2000); console.log("hello js sleep !"); }
StephaneAG
fonte
36
Esta não é uma resposta. É exatamente o mesmo que o código da pergunta, exceto um pouco mais curto.
jab
16
Espera ocupada, sério? Em JS? Por segundos? Se eu pegar um site fazendo isso, ele será bloqueado.
Mafu
35
@mafu É por isso que ele diz only for debug/dev... rolleyes
xDaizu
12
NUNCA FAÇA ISSO. Isso fará com que a CPU atinja 100% no núcleo que é executado e a bloqueie.
noego 18/12/17
3
Isso é útil, e talvez a ÚNICA maneira de dormir, em um aplicativo javascript da linha de comando, porque async / waitit não é útil.
Wheezil
177

Eu concordo com os outros pôsteres, um sono agitado é apenas uma má idéia.

No entanto, setTimeout não sustenta a execução, ele executa a próxima linha da função imediatamente após o tempo limite ser SET, não após o tempo limite expirar, para que não realize a mesma tarefa que um sono realizaria.

A maneira de fazer isso é desmembrar sua função nas partes antes e depois.

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

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

Verifique se os nomes das funções ainda descrevem com precisão o que cada peça está fazendo (IE GatherInputThenWait e CheckInput, em vez de funcPart1 e funcPart2)

Editar

Esse método atinge o objetivo de não executar as linhas de código que você decide até APÓS o tempo limite, enquanto ainda retorna o controle ao PC cliente para executar o que quer que esteja na fila.

Editar mais

Como apontado nos comentários, isso absolutamente NÃO FUNCIONA em um loop. Você pode fazer alguns hackers (feios) extravagantes para fazê-lo funcionar em um loop, mas, em geral, isso resultará em um código espaguete desastroso.

DevinB
fonte
12
Sim. Onde isso fica complicado é quando você tem um loop ou mesmo um loop aninhado. Você deve abandonar o seu para loops e ter contadores.
Nosredna
Touché. Quero dizer, ainda seria possível, mas feio e brincalhão nesse caso. Você também pode usar algumas variáveis ​​de estado booleanas estáticas, mas isso também é bastante tolo.
DevinB
2
-1 para isso. Novamente, isso não responde à pergunta. Essa é mais uma resposta para uma pergunta como "Como executar uma função de forma assíncrona", muito diferente de "Como bloquear a execução de um código".
Deepak GM
6
@Nosredna Não, você usaria um fechamento. Por exemplo: function foo(index) { setTimeout(function() { foo_continue(index); }, 10000); }e for(var X = 0; X < 3;X++) { foo(X); }- o valor de X é passado para o fooqual é reutilizado com o nome indexquando foo_continueé chamado.
Izkata 13/01
2
@ Alexander É claro que sim, porque o objetivo de setTimeout () é impedir que o navegador bloqueie, executando o código de forma assícrona. Coloque o console.log()interior foo_continue()na versão setTimeout e você obterá o mesmo resultado.
Izkata 23/03
132

Por amor a $ DEITY, por favor, não faça uma função de espera de ocupado. setTimeoute setIntervalfaça tudo o que você precisa.

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

A cada intervalo de dois segundos, oculta o texto por um segundo. Isso mostra como usar setInterval e setTimeout para mostrar e ocultar o texto a cada segundo.

Philip Rego
fonte
3
Bem, nem tudo: setInterval produz uma impressão muito melhor da pesquisa.
Annakata 04/06/09
3
O que esse pedaço de código não reteria no mecanismo JavaScript?
Deniz Dogan
10
A menos que você precise que o sono seja síncrono, nesse caso, essa é uma pergunta completamente válida.
Aaron Dufour
36
Acho que muitos de nós podemos estar esquecendo que o JavaScript não é uma linguagem apenas para navegador. Esse cara pode estar criando um utilitário de linha de comando do Nó que requer uma breve pausa sem precisar lidar com todos os problemas de escopo de variáveis ​​que acompanham o setTimeout.
Phil LaNasa
3
@PhilLaNasa: Se fechamento sintática ainda está assustando um, um sério precisa trabalhar duro e trabalhar através Nó 101.
caos
113

Sei que essa é uma pergunta antiga, mas se (como eu) você estiver usando Javascript no Rhino, poderá usar ...

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
fonte
4
Isso é uma chamada para Java?
Ken afiada
14
Isso é Java, não Javascript
RousseauAlexandre
18
@RousseauAlexandre Incorrect. É JavaScript usando Rhino (na época, poderia ser Nashorn atualmente)
mjaggard
71

Se você estiver usando jQuery, alguém realmente criou um plug-in "delay" que nada mais é do que um wrapper para 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;
};

Você pode usá-lo em uma linha de chamadas de função conforme o esperado:

$('#warning')
.addClass('highlight')
.delay(1000)
.removeClass('highlight');
Alan Plum
fonte
4
Essa não é uma solução ruim. Mantém o contexto e a cadeia.
Nosredna
39
A partir do jQuery 1.4, .delay()faz parte do jQuery (embora com semântica diferente da implementação acima). api.jquery.com/delay
Matt Ball
7
Definitivamente, o que esta pergunta estava faltando era uma resposta do jQuery . Tão feliz que conseguimos!
XDaizu 30/08/16
1
Se você precisar de um atraso entre duas chamadas independentes, sim. Se você precisar de atrasos para desacelerar um loop, não.
WGroleau
46

Também procurei a solução do sono (não o código de produção, apenas o dev / tests) e encontrei este artigo:

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

... e aqui está outro link com soluções do lado do cliente: http://www.devcheater.com/

Além disso, quando você estiver ligando alert(), seu código também será pausado, enquanto o alerta for exibido - é preciso encontrar uma maneira de não exibir o alerta, mas obter o mesmo efeito. :)

a_w
fonte
35
Eu concordo, muitas pessoas estão dizendo: "Não, não faça isso no código de produção!" Sim, eu não quero. Quero fazer isso em código de teste descartável e, como resultado, não quero gastar muito tempo criando uma solução elegante.
user435779
31

Aqui está uma solução simples usando um XMLHttpRequest síncrono:

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

conteúdo de sleep.php:

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

Agora chame-o com: sleep (5);

pguardiario
fonte
5
@ luukad, use setTimeout()se isso funcionar, mas se isso significa desvendar 1000 linhas de retornos de chamada, isso pode começar a não parecer uma piada.
Pguardiario
11
Abordagem única, embora infelizmente o XMLHttpRequests não assíncrono seja descontinuado e será removido no futuro. O que é engraçado, porque esse fato foi o que me levou a essa pergunta em primeiro lugar.
Beejor
Esta é realmente uma boa idéia IMO. Embora eu não ache que a API de suspensão (URL de solicitação) deva ser pública, pois pode ser abusada.
Vahid Amiri 12/16
@Beejor pensando sempre apenas no futuro significa viver na irrealidade futurista :-)
user1742529 20/02
bom, mas você sabe se algum dia a Internet está lenta ou o tempo de ping do site é alto, mas ele adormece o script por mais do que o tempo de discussão. Por exemplo, se você usar sleep(300)e o site demorar 150 ms para responder, o código javascript ficará em suspensão por 450ms. e se a conexão à Internet for perdida pelo navegador, ela funcionará por apenas 0ms. Portanto, não é a melhor solução
H Chauhan
30

Aqui está. Como o código diz, não seja um desenvolvedor ruim e use isso em sites. É uma função de utilitário de desenvolvimento.

// 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
fonte
17
Isso é basicamente a mesma coisa que o OP teve.
Andrew Barber #
5
Para ser mais preciso, é o que o OP pediu para uma ALTERNATIVA.
WGroleau 25/05
A solução não é boa, mas em alguns lugares async/await, infelizmente, não responde, e precisamos usá-la obrigatoriamente.
Nabi KAZ
21

Eu pessoalmente gosto do simples:

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

então:

sleep(2); // Sleeps for 2 seconds

Estou usando o tempo todo para criar um tempo de carregamento falso enquanto cria scripts no P5js

melMass
fonte
3
Eu vejo isso como a versão mais otimizada da questão principal: ela não faz nenhuma matemática dentro do loop, apenas uma comparação simples. É um pouco difícil de ler.
hegez
4
NUNCA FAÇA ISSO. Você verificou o uso da CPU enquanto esta função está funcionando? Deverá estar perto de 100% se você der tempo suficiente para isso.
noego 18/12/17
2
@hegez: Dado que o loop funcionará por uma quantidade fixa de tempo de relógio de parede, não importa o que aconteça, parece que otimizar o loop está meio fora de questão.
ShadowRanger
@noego Como assim? Acabei de testar no Nó 10, não tenho nenhuma alteração no uso da CPU
melMass 11/03
@melMass Esta função apenas bloqueia o encadeamento do nó por n segundos, mantendo a CPU 100% ocupada. Essa "solução" é uma péssima ideia por esses dois motivos (bloqueio + CPU killer). Aguardar que o HAS não seja bloqueador, portanto, assíncrono.
Jeremy Thille
20

Primeiro:

Defina uma função que você deseja executar assim:

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

Em seguida, planeje sua execução com o método setTimeout:

setTimeout(alertWorld,1000)

Observe duas coisas

  • o segundo argumento é o tempo em milissegundos
  • como primeiro argumento, você deve passar apenas o nome (referência) da função, sem os parênteses
Pablo Fernandez
fonte
19

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

verifique se a função de chamada é assíncrona

verificado e funcionando bem

Ahmed Mohammedali
fonte
1
Finalmente. A única resposta.
Jeremy Thille
18

A melhor solução para fazer as coisas parecerem o que a maioria das pessoas deseja é usar uma função anônima:

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

Provavelmente é o mais próximo que você pode chegar de algo que simplesmente faz o que você deseja.

Observe que, se você precisar de várias dormidas, isso pode ficar feio às pressas e você pode realmente precisar repensar seu design.

Mainguy
fonte
esse é o que funcionou para mim em navegadores de desktop e em um celular antigo. Os outros que eu tentei não funcionaram em todos.
Mike
10

Para navegadores, concordo que setTimeout e setInterval são o caminho a percorrer.

Mas para o código do servidor, pode ser necessária uma função de bloqueio (por exemplo, para que você possa efetivamente sincronizar o encadeamento).

Se você estiver usando o node.js e o meteoro, pode ter encontrado as limitações do uso de setTimeout em uma fibra. Aqui está o código para suspensão do servidor.

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

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

Homer6
fonte
Server may require a blocking function... Não vejo como bloquear com força o único thread do Node e deixar todo o servidor sem resposta por vários segundos é uma boa idéia, mas tanto faz
Jeremy Thille
10

Encapsularia setTimeOut em uma promessa de consistência de código com outras tarefas assíncronas: Demo in Fiddle

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

Usado assim:

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

É fácil lembrar a sintaxe se você costumava usar o Promises.

Elo
fonte
4
Por que isso é melhor do que usar setTimeout (function () {/ * do something * /}, 2000) ;?
JSideris
10

Atualização de 2019 usando Atomics.wait

Deve funcionar no nó 9.3 ou superior.

Eu precisava de um cronômetro bastante preciso no Node.js e funciona muito bem para isso. No entanto, parece que há um suporte extremamente limitado nos navegadores.

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

Executou alguns benchmarks de timer de 10 segundos.

Com o setTimeout, recebo um erro de até 7000 microssegundos. (7ms)

Com o Atomics, meu erro parece permanecer abaixo de 600 microssegundos. (0.6ms)

Atualização 2020: Resumo

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

dos quais a página do lado do servidor, por exemplo sleep.jsp, se parece

<%
try{
  Thread.sleep(Long.parseLong(request.getParameter("millis")));
}catch(InterruptedException e){}
%>
fuweichin
fonte
Na minha opinião, melhor do que a solução aceita, que não pode ser implementada como uma função simples sem async / wait no chamador.
GroovyDotCom
Sim, contanto que você está ciente de que este é o bloqueio e que geralmente não é uma coisa boa
Kapytanhook
Muito legal, mas o fato de isso ser realmente suportado no Chrome e Firefox não o torna muito viável para usos na web. (Nov 2019)
JGreatorex
9

A maioria das respostas aqui são equivocadas ou, no mínimo, desatualizadas. Não há razão para o javascript ter que ser único e, de fato, não é. Hoje, todos os navegadores convencionais oferecem suporte a trabalhadores, antes disso, outros tempos de execução de javascript, como Rhino e Node.js, suportavam multithreading.

'Javascript é único encadeado' não é uma resposta válida. Por exemplo, executar uma função de suspensão em um trabalhador não bloqueia nenhum código em execução no encadeamento da interface do usuário.

Em tempos de execução mais recentes que suportam geradores e rendimento, pode-se trazer funcionalidade semelhante à função de suspensão em um único ambiente de encadeamento:

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

Essa imitação do sono é diferente de uma verdadeira função de sono, pois não bloqueia o encadeamento. É simplesmente uma adição à função atual setTimeout do javascript. Esse tipo de funcionalidade foi implementado no Task.js e deve funcionar hoje no Firefox.

Gabriel Ratener
fonte
Os trabalhadores não são implementados no IE, pelo menos através da versão 10. O que atualmente representa uma grande quantidade de usuários.
Beejor
É verdade, e mesmo assim não é prático implementar sleepusando vários trabalhadores. Se estiver usando o Node.js., as funções do gerador já estão implementadas e podem ser usadas conforme descrito. Os principais navegadores nem todos implementaram geradores a partir de hoje.
Gabriel Ratener
8

Eu pesquisei / pesquisei algumas páginas da web em javascript sleep / wait ... e não há resposta se você quiser que o javascript "execute, atrase, execute" ... o que a maioria das pessoas conseguiu foi: "EXECUTAR, EXECUTAR (inútil coisas), EXECUTAR "ou" EXECUTAR, EXECUTAR + EXECUTAR atrasado "....

Então eu comi alguns hambúrgueres e fiquei pensando ::: aqui está uma solução que funciona ... mas você precisa cortar seus códigos de execução ... ::: sim, eu sei, isso é apenas uma refatoração mais fácil de ler .. . ainda...

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

// .................................... // example2:

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

// ................. exemplo3:

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

// .............. example4:

<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
fonte
5
Ok, isso funciona com setTimeput, mas é difícil ver o que está acontecendo. Usar o próprio setTimeout é mais fácil que isso.
9/11/11
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
fonte
É o mesmo que a pergunta real. Não faz muito sentido torná-la a resposta real.
EML
2
Não é uma boa solução - usar isso no JavaScriptExecutor do Selenium trava o navegador Chrome cerca de 50% do tempo em um MacBook Pro 2104.
esmeralda
7

A solução mais curta sem nenhuma dependência:

await new Promise(resolve => setTimeout(resolve, 5000));
k06a
fonte
Não funciona no IE11. Temos erro de sintaxe para a função de seta.
DDphp 22/01
@ Java-DK useawait new Promise(function(resolve) { setTimeout(resolve, 5000); });
k06a 22/01
6

Você não pode dormir assim em JavaScript, ou melhor, não deveria. A execução de um loop sleep ou while fará com que o navegador do usuário seja interrompido até que o loop seja concluído.

Use um cronômetro, conforme especificado no link que você referenciou.

Andrew Dunkman
fonte
6

Um cenário em que você pode querer uma função sleep () em vez de usar setTimeout () é se você tiver uma função respondendo a um clique do usuário que acabará por abrir uma nova janela pop-up, ou seja, e você iniciou algum processamento que requer um curto período para concluir antes que o pop-up seja exibido. Mover a janela aberta para um fechamento significa que ela normalmente é bloqueada pelo navegador.

verdade
fonte
6

Entendo o objetivo de uma função de suspensão, se você precisar lidar com a execução síncrona. As funções setInterval e setTimeout criam um encadeamento de execução paralelo que retorna a sequência de execução ao programa principal, que é ineficaz se você precisar esperar por um determinado resultado. É claro que se pode usar eventos e manipuladores, mas em alguns casos não é o que se pretende.

naazgull
fonte
6

Adicionando meus dois bits. Eu precisava de uma espera ocupada para fins de teste. Eu não queria dividir o código, pois isso daria muito trabalho, então é simples fazer isso por mim.

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

Não vejo nenhuma desvantagem em fazer isso e isso fez o truque para mim.

caiocpricci2
fonte
Isso pode ser compilado.
Viktor Sehr
Por favor, não faça dessa maneira. Essa é uma chamada de suspensão do bloqueio , o que significa que nenhum outro javascript pode ser executado enquanto o seu código estiver sobrecarregando o encadeamento JS.
precisa
5
@SteveMidgley "nenhum outro javascript [capaz de] executar enquanto seu código está sobrecarregando o encadeamento JS" parece-me exatamente o que o OP deseja fazer ¯_ (ツ) _ / ¯
drigoangelo
1
Acabei de executar alguns testes e parece que até um loop vazio bloqueará o navegador e a CPU (não apenas JavaScript). E o uso de forloops quase sempre é executado imediatamente, independentemente do valor máximo de i, e mesmo com o código matemático complexo colocado dentro. Portanto, a menos que você esteja esperando apenas alguns milissegundos, ainda parece que não há como dormir normalmente em JS.
Beejor
1 milhão é muito grande. Para mim 10k suficiente
Vlad
6

Isso pode ser feito usando o método de suspensão do Java. Eu testei no FF e no IE e ele não bloqueia o computador, mastiga recursos ou causa inúmeros acessos ao servidor. Parece uma solução limpa para mim.

Primeiro, você deve carregar o Java na página e disponibilizar seus métodos. Para fazer isso, eu fiz o seguinte:

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

Então, tudo o que você precisa fazer quando deseja uma pausa indolor no seu JS é:

java.lang.Thread.sleep(xxx)

Onde xxx é o tempo em milissegundos. No meu caso (como justificativa), isso fazia parte do atendimento de pedidos de back-end em uma empresa muito pequena e eu precisava imprimir uma fatura que precisava ser carregada do servidor. Fiz isso carregando a fatura (como uma página da Web) em um iFrame e depois imprimindo o iFrame. Obviamente, tive que esperar até que a página estivesse totalmente carregada para poder imprimir, então o JS teve que fazer uma pausa. Eu consegui isso fazendo com que a página da fatura (no iFrame) alterasse um campo de formulário oculto na página pai com o evento onLoad. E o código na página pai para imprimir a fatura tinha esta aparência (peças irrelevantes cortadas para maior clareza):

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

Assim, o usuário aperta o botão, o script carrega a página da fatura e aguarda, verificando a cada quarto de segundo se a página da fatura terminou de carregar e, em seguida, aparece a caixa de diálogo de impressão para que o usuário a envie à impressora. QED.

Rachael
fonte
12
Parece soulution bastante monstruoso ao considerar a coisa simples que o autor queria alcançar.
Xaralis
2
Isso depende dos Java Applets que foram descontinuados.
Vahid Amiri
6

Muitas das respostas não (diretamente) respondem à pergunta, e nem essa ...

Aqui estão meus dois centavos (ou funções):

Se você deseja menos funções desajeitadas que setTimeoute setInterval, pode envolvê-las em funções que apenas invertem a ordem dos argumentos e lhes dão nomes agradáveis:

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

Versões do CoffeeScript:

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

Você pode usá-los perfeitamente com funções anônimas:

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

Agora, lê-se facilmente como "após N milissegundos ..." (ou "a cada N milissegundo ...")

1j01
fonte
5

Para o caso específico de querer espaçar um conjunto de chamadas sendo executadas por um loop, você pode usar algo como o código abaixo com o protótipo. Sem protótipo, você pode substituir a função de atraso por 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
fonte
5

Se você estiver no node.js, poderá ver as fibras - uma extensão C nativa para o nó, uma simulação meio de multi-threading.

Ele permite que você faça um real de sleepmaneira a bloquear a execução em uma fibra, mas não bloqueia o encadeamento principal e outras fibras.

Aqui está um exemplo recente de seu próprio leia-me:

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

- e os resultados são:

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