Executar script após atraso específico usando JavaScript

189

Existe algum método JavaScript semelhante ao jQuery delay()ou wait()(para atrasar a execução de um script por um período específico)?

Niyaz
fonte

Respostas:

189

Existe o seguinte:

setTimeout(function, milliseconds);

função que pode ser passada o tempo após o qual a função será executada.

Consulte: Método da janelasetTimeout() .

Abhinav
fonte
3
Não é uma expressão que é executada, é uma função. A resposta da @Marius ilustra isso.
27412 pedrofurla
117
isso não é um atraso, é um garfo. O atraso deve funcionar no mesmo segmento.
DragonLord 31/10/12
13
Isso executará imediatamente function_reference. Para "trabalhar" (de forma assíncrona), deve ser indicado como: setTimeout (function () {MethodToCall ();}, 1000);
Bernoulli TI
6
Quero ressaltar que estamos falando de JavaScript; criar "threads" ou que ele funcione "de forma síncrona" pode ser verdade técnica e semanticamente, mas não se encaixa realmente no contexto do JavaScript, considerando que realmente não há maneira de obter um atraso com qualquer um desses métodos (você não t crie "threads" em JS como você faz em outros idiomas). Além disso, isso não será executado imediatamente, a function_referencemenos que você inclua (). Ou seja, function_referenceé exatamente isso - uma referência; a passagem function_reference()invocaria a função imediatamente.
precisa
237

Apenas para acrescentar ao que todos os outros disseram sobre setTimeout: Se você quiser chamar uma função com um parâmetro no futuro, precisará configurar algumas chamadas de função anônimas.

Você precisa passar a função como argumento para que ela seja chamada posteriormente. Com efeito, isso significa sem colchetes atrás do nome. O seguinte chamará o alerta de uma só vez e exibirá 'Hello world':

var a = "world";
setTimeout(alert("Hello " + a), 2000);

Para corrigir isso, você pode colocar o nome de uma função (como Flubba fez) ou pode usar uma função anônima. Se você precisar passar um parâmetro, precisará usar uma função anônima.

var a = "world";
setTimeout(function(){alert("Hello " + a)}, 2000);
a = "Stack Overflow";

Mas se você executar esse código, notará que, após 2 segundos, o pop-up exibirá 'Hello Stack Overflow'. Isso ocorre porque o valor da variável a mudou nesses dois segundos. Para dizer 'Olá mundo' após dois segundos, você precisa usar o seguinte trecho de código:

function callback(a){
    return function(){
        alert("Hello " + a);
    }
}
var a = "world";
setTimeout(callback(a), 2000);
a = "Stack Overflow";

Esperará 2 segundos e depois aparecerá 'Hello world'.

Marius
fonte
37

Só para expandir um pouco ... Você pode executar o código diretamente na setTimeoutchamada, mas como o @patrick diz, você normalmente atribui uma função de retorno de chamada, assim. O tempo é milissegundos

setTimeout(func, 4000);
function func() {
    alert('Do stuff here');
}
Polsonby
fonte
27

Se você realmente deseja ter uma função de bloqueio (síncrona) delay(por qualquer motivo), por que não fazer algo assim:

<script type="text/javascript">
    function delay(ms) {
        var cur_d = new Date();
        var cur_ticks = cur_d.getTime();
        var ms_passed = 0;
        while(ms_passed < ms) {
            var d = new Date();  // Possible memory leak?
            var ticks = d.getTime();
            ms_passed = ticks - cur_ticks;
            // d = null;  // Prevent memory leak?
        }
    }

    alert("2 sec delay")
    delay(2000);
    alert("done ... 500 ms delay")
    delay(500);
    alert("done");
</script>
Mario Werner
fonte
2
A dificuldade desta solução é que ela usa ativamente um processador, o que leva ao aumento do uso de energia e à diminuição dos recursos disponíveis para outros threads / processos (por exemplo, outras guias, outros programas). O sono, por outro lado, suspende temporariamente o uso de recursos do sistema por um encadeamento.
#
1
melhor usar Date.now () em vez de new Date () e não pensar em vazamentos de memória
Wayfarer
1
É claro que consome muita CPU, mas para testes rápidos e sujos funciona
Maris B.
Quero uma versão que não bloqueie o thread, para que eu possa atualizar o DOM antes de delaying (para responder a esta pergunta ). Existe alguma maneira de fazer isso?
Gui Imamura
3
Uma rotina mais compacta: atraso da função (ms) {var start_time = Date.now (); while (Date.now () - hora_início <ms); }
Duke
15

Você precisa usar o setTimeout e passar uma função de retorno de chamada. O motivo pelo qual você não pode usar a suspensão no javascript é porque você impediria a página inteira de fazer qualquer coisa nesse meio tempo. Não é um bom plano. Use o modelo de evento do Javascript e fique feliz. Não lute contra isso!

Patrick
fonte
2
Ainda assim, seria útil para fins de teste. Como adiar o envio de um formulário por alguns segundos para avaliar as alterações na página antes que uma nova solicitação HTTP seja feita.
rushinge
1
@rushinge, defina o retorno de chamada para enviar o formulário e desabilite o envio padrão do formulário
Populus
1
Má idéia para deixar um link como o código ... pois agora ele não funciona.
Emmet Arries
1
Ou você sabe, eu poderia consertar isso.
Patrick
14

Você também pode usar window.setInterval () para executar algum código repetidamente em intervalos regulares.

rcoup
fonte
2
setInterval () não deve ser usado em vez deve usar setTimeout
paul
9
setTimeout()faz isso uma vez, setInterval()faz repetidamente. Se você deseja que seu código seja executado a cada 5 segundos, setInterval()é feito para o trabalho.
Rcoup
11

Para adicionar os comentários anteriores, gostaria de dizer o seguinte:

A setTimeout()função em JavaScript não pausa a execução do script em si, mas apenas informa ao compilador para executar o código em algum momento no futuro.

Não existe uma função que possa pausar a execução incorporada ao JavaScript. No entanto, você pode escrever sua própria função que executa algo como um loop incondicional até que o tempo seja alcançado usando a Date()função e adicionando o intervalo de tempo necessário.

narasi
fonte
11

Se você só precisa testar um atraso, pode usar o seguinte:

function delay(ms) {
   ms += new Date().getTime();
   while (new Date() < ms){}
}

E então, se você quiser atrasar por 2 segundos, faça:

delay(2000);

Pode não ser o melhor para a produção. Mais sobre isso nos comentários

Christoffer
fonte
@ U2744 SNOWFLAKE Você pode tentar e ser um pouco mais preciso em seu comentário #
Christoffer
1
Bem, é um loop ocupado que esgotará as baterias de laptops e outros dispositivos móveis e provavelmente também impedirá que a interface do usuário responda (ou até seja exibida).
Ry-
@ U2744SNOWFLAKE Faz sentido. Atualizei a resposta, para o que usei essa função :) :)
Christoffer
2
Funciona bem o suficiente no desenvolvimento para uma solução rápida e suja (e temporária).
HumanInDisguise
5

por que você não pode colocar o código por trás de uma promessa? (digitado no topo da minha cabeça)

new Promise(function(resolve, reject) {
  setTimeout(resolve, 2000);
}).then(function() {
  console.log('do whatever you wanted to hold off on');
});

Al Joslin
fonte
5

A resposta simples é:

setTimeout(
    function () {
        x = 1;
    }, 1000);

A função acima aguarda 1 segundo (1000 ms) e define x como 1. Obviamente, este é um exemplo; você pode fazer o que quiser dentro da função anônima.

Luca
fonte
4

Gostei muito da explicação de Maurius (resposta mais votada) com os três métodos diferentes de chamada setTimeout.

No meu código, desejo navegar automaticamente automaticamente para a página anterior após a conclusão de um evento de salvamento do AJAX. A conclusão do evento de salvamento possui uma leve animação no CSS, indicando que o salvamento foi bem-sucedido.

No meu código, encontrei uma diferença entre os dois primeiros exemplos:

setTimeout(window.history.back(), 3000);

Este não espera pelo tempo limite - o back () é chamado quase imediatamente, independentemente do número que eu coloquei para o atraso.

No entanto, altere isso para:

setTimeout(function() {window.history.back()}, 3000);

Isso faz exatamente o que eu estava esperando.

Isso não é específico para a operação back (), o mesmo acontece com alert(). Basicamente com o alert()usado no primeiro caso, o tempo de atraso é ignorado. Quando eu rejeito o pop-up, a animação para o CSS continua.

Portanto, eu recomendaria o segundo ou terceiro método que ele descreve, mesmo se você estiver usando funções internas e não argumentos.

Doug
fonte
1

Eu tinha alguns comandos ajax que queria executar com um atraso no meio. Aqui está um exemplo simples de uma maneira de fazer isso. Estou preparado para ser rasgado em pedaços, embora para a minha abordagem não convencional. :)

//  Show current seconds and milliseconds
//  (I know there are other ways, I was aiming for minimal code
//  and fixed width.)
function secs()
{
    var s = Date.now() + ""; s = s.substr(s.length - 5);
  return s.substr(0, 2) + "." + s.substr(2);
}

//  Log we're loading
console.log("Loading: " + secs());

//  Create a list of commands to execute
var cmds = 
[
    function() { console.log("A: " + secs()); },
    function() { console.log("B: " + secs()); },
    function() { console.log("C: " + secs()); },
    function() { console.log("D: " + secs()); },
    function() { console.log("E: " + secs()); },
  function() { console.log("done: " + secs()); }
];

//  Run each command with a second delay in between
var ms = 1000;
cmds.forEach(function(cmd, i)
{
    setTimeout(cmd, ms * i);
});

// Log we've loaded (probably logged before first command)
console.log("Loaded: " + secs());

Você pode copiar o bloco de código e colá-lo em uma janela do console e ver algo como:

Loading: 03.077
Loaded: 03.078
A: 03.079
B: 04.075
C: 05.075
D: 06.075
E: 07.076
done: 08.076
JohnnyIV
fonte
1

A solução mais simples para chamar sua função com atraso é:

function executeWithDelay(anotherFunction) {
    setTimeout(anotherFunction, delayInMilliseconds);
}
Jackkobec
fonte
0

função de atraso:

/**
 * delay or pause for some time
 * @param {number} t - time (ms)
 * @return {Promise<*>}
 */
const delay = async t => new Promise(resolve => setTimeout(resolve, t));

uso dentro da asyncfunção:

await delay(1000);
Zuhair Taha
fonte
-1

Como já foi dito, setTimeout é a sua aposta mais segura.
Mas às vezes você não pode separar a lógica de uma nova função, então pode usar o Date.now () para obter milissegundos e fazer o atraso sozinho.

function delay(milisecondDelay) {
   milisecondDelay += Date.now();
   while(Date.now() < milisecondDelay){}
}

alert('Ill be back in 5 sec after you click OK....');
delay(5000);
alert('# Im back # date:' +new Date());

JavaSheriff
fonte