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

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.


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.


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.


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


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.


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

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

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


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.



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

-2

usando angularjs:

$timeout(function(){
if(yourvariable===-1){
doSomeThingAfter5Seconds();
}
},5000)

-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

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