Aguarde 5 segundos antes de executar a próxima linha

313

Esta função abaixo não funciona como eu quero; sendo um novato em JS, não consigo entender o porquê.

Eu preciso esperar 5 segundos antes de verificar se newStateé -1.

Atualmente, ele não espera, apenas verifica imediatamente.

function stateChange(newState) {
  setTimeout('', 5000);

  if(newState == -1) {
    alert('VIDEO HAS STOPPED');
  }
}
copyflake
fonte

Respostas:

323

Você deve inserir seu código na função de retorno de chamada fornecida para setTimeout:

function stateChange(newState) {
    setTimeout(function () {
        if (newState == -1) {
            alert('VIDEO HAS STOPPED');
        }
    }, 5000);
}

Qualquer outro código será executado imediatamente.

Joseph Silber
fonte
4
O principal problema é que, em alguns casos (especificamente testando), isso é lamentavelmente inadequado. E se você precisar dormir por 500 ms antes de retornar da função, por exemplo, para simular uma solicitação http assíncrona lenta ?
A.Grandt
14
Se por "teste" você quer dizer testes de unidade: sua estrutura de teste deve ter uma maneira de executar testes assíncronos. Se você quer dizer teste manual: a guia Rede do Chrome possui um menu suspenso Otimização para simular solicitações lentas.
Joseph Silber
1
e se eu desenvolver uma extensão chrome e o último valor avaliado no script injetado me fornecer o resultado; e eu preciso de alguns atrasos?
Mirek 30/05/19
184

Você realmente não deveria estar fazendo isso , o uso correto do tempo limite é a ferramenta certa para o problema do OP e em qualquer outra ocasião em que você queira executar algo após um período de tempo. Joseph Silber demonstrou isso bem em sua resposta. No entanto, se, em alguns casos de não produção, você realmente quiser travar o encadeamento principal por um período de tempo, isso será possível.

function wait(ms){
   var start = new Date().getTime();
   var end = start;
   while(end < start + ms) {
     end = new Date().getTime();
  }
}

Com execução no formato:

console.log('before');
wait(7000);  //7 seconds in milliseconds
console.log('after');

Cheguei aqui porque estava construindo um caso de teste simples para sequenciar uma mistura de operações assíncronas em torno de operações de bloqueio de longa execução (ou seja, manipulação cara do DOM) e esta é a minha operação de bloqueio simulada. Como esse trabalho é adequado, pensei em publicá-lo para qualquer pessoa que chegar aqui com um caso de uso semelhante. Mesmo assim, ele está criando um objeto Date () em um loop while, o que pode sobrecarregar o GC se ele for executado por tempo suficiente. Mas não posso enfatizar o suficiente, isso é adequado apenas para testes, para criar qualquer funcionalidade real, você deve consultar a resposta de Joseph Silber.

Microfone
fonte
7
Isso não impedirá a execução do javascript.
Terry Lin
23
@TerryLin Tente executá-lo.
Mic
6
Então, basicamente, você está perdendo tempo de CPU. Isso não é uma espera, pois você não está colocando o encadeamento no modo de suspensão, permitindo que o processador principal se concentre em outras tarefas.
21417 Kyordhel
6
A suspensão do thread do @Gzork é apenas uma maneira de implementar uma função de espera e, infelizmente, não está disponível no contexto do javascript do lado do cliente. No entanto, se você pensa que outras tarefas assíncronas no cliente serão concluídas enquanto estiver em execução, obviamente você não a testou. Embora eu o usasse no thread principal, montei um violino ilustrando como, mesmo que isso seja chamado por meio de um setTimeout, ele ainda interrompe outros eventos assíncronos jsfiddle.net/souv51v3/1 - você encontrará até o A própria janela JSFiddle fica sem resposta enquanto é concluída.
Mic
1
Solução horrível IMHO - monopoliza a CPU enquanto está "dormindo". O caminho certo para dormir é via async / aguarde ala esta resposta stackoverflow.com/questions/951021/… ou Etienne's.
David Simic
163

Aqui está uma solução usando a nova sintaxe assíncrona / aguardada .

Verifique o suporte ao navegador, pois esse é um novo recurso introduzido no ECMAScript 6.

Função útil:

const delay = ms => new Promise(res => setTimeout(res, ms));

Uso:

const yourFunction = async () => {
  await delay(5000);
  console.log("Waited 5s");

  await delay(5000);
  console.log("Waited an additional 5s");
};

A vantagem dessa abordagem é que ela faz seu código parecer e se comportar como código síncrono.

Etienne Martin
fonte
Não é necessário o ECMAScript 6: se você já estiver usando promessas para fazer o carregamento assíncrono e apenas quiser imitar uma parte da cadeia demorando muito tempo, poderá adicionar esta função wait () à cadeia.
Dovev Hefetz
2
Esta é realmente a melhor resposta com a nova sintaxe. Eu tive problemas com o uso da solução wait () acima.
Pianoman102 22/03/19
37

Use uma função de atraso como esta:

var delay = ( function() {
    var timer = 0;
    return function(callback, ms) {
        clearTimeout (timer);
        timer = setTimeout(callback, ms);
    };
})();

Uso:

delay(function(){
    // do stuff
}, 5000 ); // end delay

Créditos: como atrasar o manipulador .keyup () até que o usuário pare de digitar?

Kai Noack
fonte
36

Você não deve apenas tentar pausar 5 segundos em javascript. Não é assim que funciona. Você pode agendar uma função do código para ser executada em 5 segundos a partir de agora, mas é necessário colocar o código que deseja executar posteriormente em uma função e o restante do seu código após essa função continuará sendo executado imediatamente.

Por exemplo:

function stateChange(newState) {
    setTimeout(function(){
        if(newState == -1){alert('VIDEO HAS STOPPED');}
    }, 5000);
}

Mas, se você tiver um código como este:

stateChange(-1);
console.log("Hello");

A console.log()declaração será executada imediatamente. Ele não irá esperar até que o tempo limite seja acionado na stateChange()função. Você não pode simplesmente pausar a execução do javascript por um tempo predeterminado.

Em vez disso, qualquer código que você deseja executar atrasos deve estar dentro da setTimeout()função de retorno de chamada (ou chamado a partir dessa função).

Se você tentou "pausar" fazendo um loop, basicamente "travou" o intérprete Javascript por um período de tempo. Como o Javascript executa seu código em apenas um único encadeamento, quando você faz um loop, nada mais pode ser executado (nenhum outro manipulador de eventos pode ser chamado). Portanto, aguardar repetidamente a alteração de uma variável nunca funcionará porque nenhum outro código pode ser executado para alterar essa variável.

jfriend00
fonte
31
Você não pode simplesmente pausar a execução do javascript por um tempo predeterminado . Eu acho que você quer dizer que não deveria, pois você pode (se quiser se enforcar):var t = new Date().getTime(); while (new Date().getTime() < t + millisecondsToLockupBrowser);
Joseph Silber
9
@JosephSilber - Tudo bem, você poderia fazer isso, mas, na prática, isso não funciona, pois muitos navegadores exibem uma caixa de diálogo informando que um script ficou sem resposta E é uma experiência horrível para o usuário e prejudica a vida útil da bateria e a página é pendurado enquanto fazia isso e ... Isso seria ruim.
precisa saber é
12
Bem, é claro que isso seria horrível, e ninguém jamais deveria fazer isso. Eu simplesmente não pude resistir ao meu interior "bem" . Desculpe.
Joseph Silber
31

Se você estiver em uma função assíncrona, basta fazê-lo em uma linha:

console.log(1);
await new Promise(resolve => setTimeout(resolve, 3000)); // 3 sec
console.log(2);

Observe que se o destino for NodeJS, será mais eficiente usá-lo (é uma função setTimeout prometida predefinida):

await setTimeout[Object.getOwnPropertySymbols(setTimeout)[0]](3000) // 3 sec
Shl
fonte
Qual é a diferença entre as duas implementações?
EAzevedo
1
Atualmente, não há diferença. Mas se em algum momento o nó decidir torná-lo mais rápido / seguro / mais eficiente, você usará a versão do nó js antecipadamente. Embora seja mais provável que a legibilidade seja o fator-chave para a maioria das pessoas, nesse caso, é melhor usar a primeira maneira.
Shl
Obrigado. Sua resposta resolveu um problema que eu já enfrento há três dias. Obrigado.
EAzevedo
8

Tente o seguinte:

//the code will execute in 1 3 5 7 9 seconds later
function exec() {
    for(var i=0;i<5;i++) {
        setTimeout(function() {
            console.log(new Date());   //It's you code
        },(i+i+1)*1000);
    }
}
Steve Jiang
fonte
7

A melhor maneira de criar uma função como esta para aguardar em mili segundos, esta função aguardará os milissegundos fornecidos no argumento:

function waitSeconds(iMilliSeconds) {
    var counter= 0
        , start = new Date().getTime()
        , end = 0;
    while (counter < iMilliSeconds) {
        end = new Date().getTime();
        counter = end - start;
    }
}

Jitendra Pal - JP
fonte
3

Com base na resposta de Joseph Silber , eu faria assim, um pouco mais genérico.

Você teria sua função (vamos criar uma com base na pergunta):

function videoStopped(newState){
   if (newState == -1) {
       alert('VIDEO HAS STOPPED');
   }
}

E você pode ter uma função de espera:

function wait(milliseconds, foo, arg){
    setTimeout(function () {
        foo(arg); // will be executed after the specified time
    }, milliseconds);
}

No final, você teria:

wait(5000, videoStopped, newState);

Essa é uma solução, prefiro não usar argumentos na função de espera (para ter apenas em foo();vez de foo(arg);), mas é por exemplo.

Sylhare
fonte
3

Esta solução vem da documentação do React Native para um controle de atualização :

function wait(timeout) {
    return new Promise(resolve => {
        setTimeout(resolve, timeout);
    });
}

Para aplicar isso à pergunta do OP, você pode usar esta função em coordenação com await:

await wait(5000);
if (newState == -1) {
    alert('Done');
}
bearacuda13
fonte
1

Você pode adicionar atraso fazendo pequenas alterações em sua função (assíncrona e aguardando).

const add5SecondsDelay = () => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('5 seconds');
    }, 50000);
  });
}

async function asyncFunctionCall() {

  console.log("stpe-1"); 
  const result = await add5SecondsDelay ();
  console.log("step-2 after 5 seconds delay"); 

}

asyncFunctionCall();
p.durga shankar
fonte
-2

usando angularjs:

$timeout(function(){
if(yourvariable===-1){
doSomeThingAfter5Seconds();
}
},5000)
Dr. Abbos
fonte
-2

Criar nova função Js

function sleep(delay) {
        var start = new Date().getTime();
        while (new Date().getTime() < start + delay);
      }

Chame a função quando quiser atrasar a execução. Use milissegundos em int para o valor do atraso.

####Some code
 sleep(1000);
####Next line
Madushanka Sampath
fonte
3
Isso consumirá muitos recursos.
awavi
-2

Eu usei para rodar jogos de PC a partir do Edge ou IE. E fecha automaticamente o IE Edge após 7 segundos.

Firefox e Google Chrome não podem ser usados ​​para iniciar jogos dessa maneira.

<html<body>
<a href="E:\game\game.exe" name="game" onmouseout="waitclose(7000);"> game
<img src="game.jpg" width="100%" height="97%" ></a>
<script>
function waitclose(ms){
 var start = new Date().getTime();var end=start;
 while(end < start + ms) {end = new Date().getTime();}
window.open('', '_self', ''); window.close();
}
</script>
</body></html>
user4565320
fonte