Como posso esperar no Node.js (Javascript), preciso fazer uma pausa por um período de tempo


385

Estou desenvolvendo um console como script para necessidades pessoais. Eu preciso fazer uma pausa por um longo período de tempo, mas, a partir da minha pesquisa, o node.js não tem como parar conforme necessário. Está ficando difícil ler as informações dos usuários após um período de tempo ... Eu vi alguns códigos por aí, mas acredito que eles precisam ter outro código dentro deles para que funcionem, como:

setTimeout(function() {
}, 3000);

No entanto, eu preciso de tudo após esta linha de código para executar após o período de tempo.

Por exemplo,

//start-of-code
console.log('Welcome to My Console,');
some-wait-code-here-for-ten-seconds..........
console.log('Blah blah blah blah extra-blah');
//endcode. 

Eu também vi coisas como

yield sleep(2000);

Mas o node.js não reconhece isso.

Como posso conseguir essa pausa prolongada?


3
hows sobre você marcar uma dessas pessoas como resposta correta :)
Billybonks

11
@ Christopher Allen, Talvez não seja relevante, mas faz o trabalho: require("child_process").execSync('php -r "sleep($argv[1]);" ' + seconds);
Haitham Sweilem 4/16

O módulo node-sleep npm pode fazer o truque (no entanto, eu só o usaria para depuração) #
Julian Soro

Respostas:


211

A melhor maneira de fazer isso é dividir seu código em várias funções, assim:

function function1() {
    // stuff you want to happen right away
    console.log('Welcome to My Console,');
}

function function2() {
    // all the stuff you want to happen after that pause
    console.log('Blah blah blah blah extra-blah');
}

// call the first chunk of code right away
function1();

// call the rest of the code and have it execute after 3 seconds
setTimeout(function2, 3000);

É semelhante à solução do JohnnyHK , mas muito mais simples e fácil de estender.


7
@LucasSeveryn Você está fazendo algo errado, então. Este é um padrão de design básico.
Elliot Bonneville

E o que você faz quando o início da função não está apenas a uma função, mas a 10 arquivos do código que precisa ser dessincronizado?
Cyril Duchon-Doris

10
@ CyrilDuchon-Doris O que?
AturSams

3
usar @ resposta de machineghost para uma solução baseada elegante promessa que não requer nenhum código personalizado e suportes aguardam / async
Dane Macaulay

Isso é assíncrono, significa que, se a função1 terminar antes de 3 segundos, eles começarão a se sobrepor. Então você nem pode voltar e quase nunca é utilizável. A única maneira que eu encontrei até agora estava usando #debugger;
Cristian Traìna

427

Uma nova resposta para uma pergunta antiga. Hoje ( janeiro de 2017 junho de 2019) é muito mais fácil. Você pode usar a nova async/awaitsintaxe . Por exemplo:

async function init() {
  console.log(1);
  await sleep(1000);
  console.log(2);
}

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

Para usar async/awaitimediatamente, sem instalar e plug-ins, é necessário usar o nó-v7 ou o nó-v8, usando o --harmonysinalizador

Atualização junho de 2019: Ao usar as versões mais recentes do NodeJS, você pode usá-lo imediatamente. Não há necessidade de fornecer argumentos de linha de comando. Até o Google Chrome o suporta hoje.

Atualização em maio de 2020: em breve você poderá usar a awaitsintaxe fora de uma função assíncrona. No nível superior, como neste exemplo

await sleep(1000)
function sleep(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
} 

A proposta está no estágio 3 . Você pode usá-lo hoje usando o webpack 5 (alpha),

Mais informações:


5
Eu acho que você esqueceu a awaitpalavra - chave na frente desleep(1000)
Ryan Jarvis

6
Essa realmente deve ser a resposta, o pacote sleep node.js pode ser problemático.
Stuart Allen

4
Melhor solução, na verdade
Kostas Siabanis

40
let sleep = ms => new Promise(resolve => setTimeout(resolve, ms));Para os fãs de oneliner como eu :)
Predrag Stojadinovic

21
let sleep = require('util').promisify(setTimeout);funciona no nó 7.6+ e melhora a legibilidade
BrianHVB

216

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

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

14
"O auge da sofisticação é a simplicidade." - Clare Booth Luce. Esta é de longe a melhor resposta, IMO.
precisa

3
Obviamente, isso é muito mais recente do que as outras respostas, mas é o mais elegante a partir de 2018 que realiza o trabalho em uma linha sem nenhum outro impacto no código.
Herick

11
Essa é boa. Você deve estar usando o NodeJS 7.6.0 ou superior. Não funcionará em versões mais antigas.
Ryan Shillington

5
let sleep = require('util').promisify(setTimeout);é três personagens mais tempo, mas reutilizável e mais legível imo
BrianHVB

2
Para evitar uma reclamação de exclusão, chame-a em resolvevez de done. Ou sejaawait new Promise(resolve => setTimeout(resolve, 5000))
Darren Cozinhe

150

Coloque o código que você deseja executar após o atraso no setTimeoutretorno de chamada:

console.log('Welcome to My Console,');
setTimeout(function() {
    console.log('Blah blah blah blah extra-blah');
}, 3000);

2
Essa é uma prática extremamente confusa e geralmente ruim, especialmente se o OP desejar que o restante do programa seja executado após esse atraso. Veja minha resposta.
precisa saber é o seguinte

32
@ ElliotBonneville É apenas um exemplo para ilustrar o conceito. Obviamente, você pode (deve) incluir o código em uma chamada de função em vez de usar o código embutido, como em qualquer outro lugar.
precisa saber é o seguinte

@ChristopherKemp: Acontece que o Node.js tem uma solução para isso chamada node-fibers. Confira.
precisa saber é o seguinte

Essa é uma ótima solução, principalmente se você não deseja executar nenhum código, apenas imitando um método "sleep" dentro de um loop. Nada de errado com este exemplo.
Halfstop 25/10/16

este é perfeito para atrasar sobre os pedidos provenientes de cliente, eu usei essa abordagem para testar meus carregamento spinners no lado do cliente
Moein Rahimi

145

Esta é uma técnica simples de bloqueio:

var waitTill = new Date(new Date().getTime() + seconds * 1000);
while(waitTill > new Date()){}

Está bloqueando na medida em que nada mais acontecerá no seu script (como retornos de chamada). Mas como esse é um script de console, talvez seja o que você precisa!


27
horrível ou não, faz um simples wait, bloqueia e funciona para algum propósito de teste. Exatamente o que eu estava procurando.
Clijsters

8
responde perfeitamente à pergunta sem bibliotecas de terceiros e é simples. No entanto, as pessoas dizem "horrível" .... Isso é ótimo por exemplo, para simular a carga da CPU pesado etc. Btw muito semelhante a esta phpied.com/sleep-in-javascript
Don Cheadle

2
Além disso, essa é a abordagem necessária se você estiver tentando simular algo que diminuiria o ciclo do evento, retardando também outros usuários / conexões. Adicionar retornos de chamada atrasados ​​não afetará outros usuários / conexões.
Don Cheadle

13
Isto é um spin-wait.
Mike Atlas

7
@ Ali que parece ser o objetivo.
Félix Gagnon-Grenier

63

No nó 7.6.0 ou superior

O nó suporta a espera nativamente:

const sleep = (waitTimeInMs) => new Promise(resolve => setTimeout(resolve, waitTimeInMs));

se você pode usar funções assíncronas:

await sleep(10000); // sleep for 10 seconds

ou:

sleep(10000).then(() => {
  // This will execute 10 seconds from now
});

Nas versões mais antigas do nó (resposta original)

Eu queria um sono assíncrono que funcionasse no Windows e Linux, sem sobrecarregar minha CPU com um longo loop. Tentei o pacote de suspensão, mas ele não foi instalado na minha caixa do Windows. Acabei usando:

https://www.npmjs.com/package/system-sleep

Para instalá-lo, digite:

npm install system-sleep

No seu código,

var sleep = require('system-sleep');
sleep(10*1000); // sleep for 10 seconds

Funciona como um encanto.


11
Grande resposta graças - ele fez algum código impossível possível - este não é um spin-espera
danday74

11
Em pesquisas adicionais, este módulo conta com o deasync, que é extraído de outro repositório do deasync github. O repo original adverte para não usá-lo, pois é um hack. Funciona, mas não em todas as plataformas, portanto, se você precisar de uma solução de plataforma cruzada, evite esta.
danday74

11
Sim, eu nunca experimentei probs com ele e é ótimo para dev - sob o capô, acredito que ele depende de C ou C ++, que está amplamente disponível, mas acho que em algumas máquinas não é e é quando falha, e é por isso que causa problemas - se ele falhar sono sistema cai de volta para uma espera de rotação que vai congelar a execução de código
danday74

11
Este pacote não funciona no Mac OS e, portanto, não é compatível com outras versões e, portanto, não é viável. Veja github.com/jochemstoel/nodejs-system-sleep/issues/4
nuzzolilo

11
@Nuzzolilo Isso é estranho. Temos um desenvolvedor no Mac OS e ele nunca mencionou nada de errado. Eu suspeito que é uma versão específica do Mac OS. Também atualizei esta resposta, pois o sono é basicamente incorporado às versões mais recentes do NodeJS.
Ryan Shillington

62

Função de sono simples e elegante usando Javascript moderno

function sleep(millis) {
    return new Promise(resolve => setTimeout(resolve, millis));
}

Sem dependências, sem retorno de chamada; é isso aí :-)


Considerando o exemplo dado na pergunta, é assim que dormimos entre dois logs do console:

async function main() {
    console.log("Foo");
    await sleep(2000);
    console.log("Bar");
}

main();

A "desvantagem" é que sua função principal agora também precisa ser async. Mas, considerando que você já está escrevendo um código Javascript moderno, provavelmente você está (ou pelo menos deveria estar!) Usando async/ em awaittodo o seu código, então isso realmente não é um problema. Todos os navegadores modernos hoje suportam .

Fornecendo uma pequena visão da sleepfunção para aqueles que não estão acostumados async/awaite operadores de seta gorda, esta é a maneira detalhada de escrevê-la:

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

No entanto, o uso do operador de seta gorda o torna ainda menor (e mais elegante).


11
Você também pode escrever a função de suspensão sem a asynctecla e deixando tudo o mesmo. Provavelmente é mais claro com o asyncpensamento.
Kevin Peña

Boa captura, @ KevinPeña. De fato, acho que prefiro sem async. Editou minha resposta com sua sugestão. Eu não acho que isso torna o código mais claro; por isso, eu recorreria ao JSDoc.
Lucio Paiva

8
Eu gosto de ter o seguinte one-liner em meus scripts:const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
korya 23/01


34

Essa pergunta é bastante antiga, mas recentemente a V8 adicionou geradores que podem realizar o que o OP solicitou. Geralmente, os geradores são mais fáceis de usar para interações assíncronas com a assistência de uma biblioteca, como suspender ou executar com gen .

Aqui está um exemplo usando o suspend:

suspend(function* () {
    console.log('Welcome to My Console,');
    yield setTimeout(suspend.resume(), 10000); // 10 seconds pass..
    console.log('Blah blah blah blah extra-blah');
})();

Leitura relacionada (por meio de autopromoção desavergonhada): Qual é o grande problema dos geradores? .


2
Boa resposta - Mas deve leryield setTimeout(suspend.resume(), 10000);
edhubbell

11
Obrigado, @edhubbell. Esta resposta foi baseada em uma versão muito antiga do suspend, mas você está certo quanto à mais recente. Vou atualizar a resposta.
jmar777

qual é a versão do nó?
precisa saber é o seguinte

11
@ danday74 Não me lembro exatamente quando eles não foram sinalizados, mas existem desde a v0.12 atrás da --harmonybandeira e, de acordo com node.green, estão pelo menos disponíveis sem sinalizadores desde a v4.8.4: node.green/#ES2015-functions-generators-basic-functionality . Observe, no entanto, que a async/awaitsintaxe mais recente fornece uma solução melhor para isso agora, sem a necessidade de bibliotecas extras como suspend. Veja esta resposta para um exemplo: stackoverflow.com/a/41957152/376789 . As funções assíncronas estão disponíveis (sem sinalizadores) desde a v7.10.
precisa saber é o seguinte

20

No Linux / nodejs, isso funciona para mim:

const spawnSync = require ('child_process'). spawnSync;

var sono = spawnSync ('sono', [1.5]);

Está bloqueando, mas não é um ciclo de espera ocupado.

O tempo especificado é em segundos, mas pode ser uma fração. Não sei se outros sistemas operacionais têm um comando semelhante.


sleepé praticamente onipresente e muito útil desde os primeiros dias do UNIX en.wikipedia.org/wiki/Sleep_%28Unix%29 . Apenas "não raro" os que talvez não existiria é windows (no entanto, há que você poderia tentarchild_process.spawnSync('timeout', ['/T', '10'])
humanityANDpeace

17

Se você deseja "codificar golfe", você pode fazer uma versão mais curta de algumas das outras respostas aqui:

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

Mas, na verdade, a resposta ideal, na minha opinião, é usar a utilbiblioteca do Node e sua promisifyfunção, projetada exatamente para esse tipo de coisa (criando versões baseadas em promessas de coisas não baseadas em promessas anteriormente existentes):

const util = require('util');
const sleep = util.promisify(setTimeout);

Em ambos os casos, você pode pausar simplesmente usando awaitpara chamar sua sleepfunção:

await sleep(1000); // sleep for 1s/1000ms

Na verdade, usando util.promisify, não é possível chamar suspensão sem fornecer também um retorno de chamada. nodejs.org/api/…
Howie

11
Você está sentindo falta do await. Ele meio que cria um retorno de chamada, pausa as coisas e reinicia o código quando esse retorno de chamada. O retorno de chamada retorna com um valor, mas não nos preocupamos com isso neste caso, portanto, não resta nada à esquerda await.
precisa

11
escreva-o em uma linha para usar o código golf;) const sleep = require ('util'). promisify (setTimeout);
Fabian

14

Recentemente, criei uma abstração mais simples chamada wait.for para chamar funções assíncronas no modo de sincronização (com base nas fibras do nó). Há também uma versão baseada nos próximos Geradores ES6.

https://github.com/luciotato/waitfor

Usando wait.for , você pode chamar qualquer função nodejs assíncrona padrão, como se fosse uma função de sincronização, sem bloquear o loop de eventos do nó.

Você pode codificar sequencialmente quando precisar, o que é (suponho) perfeito para simplificar seus scripts para uso pessoal.

usando wait.for, seu código será:

require('waitfor')

..in a fiber..
//start-of-code
console.log('Welcome to My Console,');
wait.miliseconds(10*1000); //defined in waitfor/paralell-tests.js - DOES NOT BLOCK
console.log('Blah blah blah blah extra-blah');
//endcode. 

Também qualquer função assíncrona pode ser chamada no modo Sincronizar . Veja os exemplos.


TypeError: Object #<Object> has no method 'miliseconds'
CaffeineAddiction

o comentário diz: "// definido em waitfor / paralell-tests.js" pegue-o nesse arquivo.
Lucio M. Tato 14/03

2
depois que o obtive, wait.for/paralell-tests.jsencontrei outros erros relacionados a propriedades indefinidas, etc. Então, eu também precisei copiá-los. Por que você não organiza o código de maneira que isso não seja necessário?
user907860

O Wait.for e outras soluções de fibra abriram um mundo totalmente novo para mim! Eu votaria nisso um milhão de vezes, se pudesse. Embora a maioria da comunidade nodejs se oponha às fibras, acho que elas são uma adição fantástica e definitivamente têm seu lugar quando se trata de um inferno de retorno de chamada.
Levi Roberts

7

Como o mecanismo javascript (v8) executa o código com base na sequência de eventos na fila de eventos, não é rigoroso que o javascript acione exatamente a execução após o tempo especificado. Ou seja, quando você define alguns segundos para executar o código posteriormente, o código de acionamento é puramente baseado na sequência na fila de eventos. Portanto, disparar a execução do código pode levar mais do que o tempo especificado.

Então o Node.js segue,

process.nextTick()

para executar o código posteriormente, em vez de setTimeout (). Por exemplo,

process.nextTick(function(){
    console.log("This will be printed later");
});

2

Com o ES6 suportando Promises, podemos usá-los sem nenhum auxílio de terceiros.

const sleep = (seconds) => {
    return new Promise((resolve, reject) => {
        setTimeout(resolve, (seconds * 1000));
    });
};

// We are not using `reject` anywhere, but it is good to
// stick to standard signature.

Em seguida, use-o assim:

const waitThenDo(howLong, doWhat) => {
    return sleep(howLong).then(doWhat);
};

Observe que a doWhatfunção se torna o resolveretorno de chamada dentro do new Promise(...).

Observe também que isso é sono ASSÍNCRONO. Não bloqueia o loop de eventos. Se você precisar bloquear o sono, use esta biblioteca que realiza o bloqueio do sono com a ajuda de ligações do C ++. (Embora a necessidade de um sono bloqueador no Node como ambientes assíncronos seja rara.)

https://github.com/erikdubbelboer/node-sleep


1
let co = require('co');
const sleep = ms => new Promise(res => setTimeout(res, ms));

co(function*() {
    console.log('Welcome to My Console,');
    yield sleep(3000);
    console.log('Blah blah blah blah extra-blah');
});

Este código acima é o efeito colateral do problema do inferno de retorno de chamada assíncrona do Javascript. Esta é também a razão pela qual acho que faz do Javascript uma linguagem útil no back-end. Na verdade, esta é a melhoria mais emocionante introduzida no Javascript moderno na minha opinião. Para entender completamente como ele funciona, como o gerador funciona precisa ser totalmente compreendido. A functionpalavra-chave seguida por a *é chamada de função geradora em Javascript moderno. O pacote npm coforneceu uma função runner para executar um gerador.

Essencialmente, a função gerador forneceu uma maneira de pausar a execução de uma função com a yieldpalavra - chave, ao mesmo tempo, yieldem uma função geradora, permitindo a troca de informações entre o gerador e o chamador. Isso forneceu um mecanismo para o chamador extrair dados de uma promisechamada assíncrona e passar os dados resolvidos de volta ao gerador. Efetivamente, ele faz uma chamada assíncrona síncrona.


Embora esse código possa responder à pergunta, fornecer um contexto adicional sobre como e / ou por que resolve o problema melhoraria o valor a longo prazo da resposta.
Donald Duck

Obrigado @DonaldDuck. O código na minha resposta é provavelmente a parte mais interessante da melhoria do Javascript. Estou tão surpreso que algumas pessoas super inteligentes pensem dessa maneira para resolver o problema do inferno de retorno de chamada.
Qian Chen


0

Se você apenas precisar suspender para fins de teste, a execução atual do encadeamento tente o seguinte:

function longExecFunc(callback, count) {

    for (var j = 0; j < count; j++) {
        for (var i = 1; i < (1 << 30); i++) {
            var q = Math.sqrt(1 << 30);
        }
    }
    callback();
}
longExecFunc(() => { console.log('done!')}, 5); //5, 6 ... whatever. Higher -- longer

0

simples, vamos esperar por 5 segundos para que algum evento aconteça (que seria indicado pela variável concluída configurada como true em outro lugar no código) ou quando o tempo limite expirar, verificaremos a cada 100 ms

    var timeout=5000; //will wait for 5 seconds or untildone
    var scope = this; //bind this to scope variable
    (function() {
        if (timeout<=0 || scope.done) //timeout expired or done
        {
            scope.callback();//some function to call after we are done
        }
        else
        {
            setTimeout(arguments.callee,100) //call itself again until done
            timeout -= 100;
        }
    })();

0

Para algumas pessoas, a resposta aceita não está funcionando, encontrei esta outra resposta e está funcionando para mim: Como posso passar um parâmetro para um retorno de chamada setTimeout ()?

var hello = "Hello World";
setTimeout(alert, 1000, hello); 

'olá' é o parâmetro que está sendo passado, você pode passar todos os parâmetros após o tempo limite. Obrigado a @Fabio Phms pela resposta.


0

Em vez de fazer todos esses setTimeout, sleep e muitas outras coisas, é melhor usar

const delay = require('delay');
await delay(2000); // will wait for 2 seconds before executing next line of code

Você pode explicar o que é 'atraso' e vincular-se aos documentos? Porque é melhor?
boycy

-2

As outras respostas são ótimas, mas pensei em usar um tato diferente.

Se tudo o que você está realmente procurando é diminuir a velocidade de um arquivo específico no linux:

 rm slowfile; mkfifo slowfile; perl -e 'select STDOUT; $| = 1; while(<>) {print $_; sleep(1) if (($ii++ % 5) == 0); }' myfile > slowfile  &

nó myprog slowfile

Isso durará 1 segundo a cada cinco linhas. O programa do nó será tão lento quanto o gravador. Se estiver fazendo outras coisas, eles continuarão na velocidade normal.

O mkfifo cria um tubo primeiro a entrar, primeiro a sair. É o que faz isso funcionar. A linha perl escreverá tão rápido quanto você desejar. O $ | = 1 diz não armazenar em buffer a saída.


-3

Eu montei, depois de ler as respostas nesta pergunta, uma função simples que também pode fazer um retorno de chamada, se você precisar:

function waitFor(ms, cb) {
  var waitTill = new Date(new Date().getTime() + ms);
  while(waitTill > new Date()){};
  if (cb) {
    cb()
  } else {
   return true
  }
}

-4

Para mais informações sobre

yield sleep(2000); 

você deve verificar o Redux-Saga . Mas é específico para sua escolha do Redux como sua estrutura de modelo (embora estritamente não seja necessário).

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.