setTimeout ou setInterval?


763

Tanto quanto posso dizer, esses dois pedaços de javascript se comportam da mesma maneira:

Opção A:

function myTimeoutFunction()
{
    doStuff();
    setTimeout(myTimeoutFunction, 1000);
}

myTimeoutFunction();

Opção B:

function myTimeoutFunction()
{
    doStuff();
}

myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);

Existe alguma diferença entre usar setTimeout e setInterval ?


6
Se você gostaria de algumas boas detalhes sobre como temporizadores no trabalho JS, John Resig escreveu um bom artigo sobre este tema
— Rafael

9
há também a diferença óbvia de que setTimeout requer que a linha extra de código para mantê-lo de propagação, que tem a desvantagem de ser um problema de manutenção, mas o benefício de permitir que você alterar o período facilmente
— annakata


4
Obrigado @JapanPro, mas eu realmente nunca tive problemas para fazer com que os intervalos funcionassem. Este post foi sobre qual era a diferença e qual deveria ser usada.
— precisa saber é o seguinte

Respostas:


670

Eles essencialmente tentam fazer a mesma coisa, mas a setIntervalabordagem será mais precisa do que a setTimeoutabordagem, pois setTimeoutaguarda 1000ms, executa a função e define outro tempo limite. Portanto, o período de espera é realmente um pouco superior a 1000ms (ou muito mais, se a sua função demorar muito para ser executada).

Embora se possa pensar que isso setIntervalserá executado exatamente a cada 1000ms, é importante notar que setIntervalisso também atrasará, já que o JavaScript não é uma linguagem multithread, o que significa que - se houver outras partes do script em execução - o intervalo terá esperar que isso termine.

No presente violino , você pode ver claramente que o tempo limite vai cair para trás, enquanto o intervalo é quase o tempo todo em quase 1 chamada / segundo (qual o script está tentando fazer). Se você alterar a variável de velocidade na parte superior para algo pequeno como 20 (o que significa que ela tentará executar 50 vezes por segundo), o intervalo nunca alcançará uma média de 50 iterações por segundo.

O atraso é quase sempre insignificante, mas se você estiver programando algo realmente preciso, opte por um cronômetro de autoajuste (que basicamente é um cronômetro de tempo limite que se ajusta constantemente ao atraso criado)


4
Andy teve uma sugestão semelhante. Hipoteticamente, isso significa que, se o método demorar mais de 1000ms para ser executado, você poderá ter mais de um em execução simultaneamente?
— Damovisa

14
Teoricamente, sim. Na prática, não, já que o Javascript não suporta multithreading. Se o seu código demorar mais de 1000 ms, congelará o navegador.
— Kamiel Wanrooij

61
Tecnicamente, o código não será executado exatamente a cada 1000ms, pois depende da resolução do temporizador e se outro código já está em execução. Seu ponto ainda permanece.
— Matthew Crumley

10
setInterval é diferente de duas maneiras, 1. setInterval não é recursivo e setInterval chamará sua função pela primeira vez após o horário informado, enquanto setTimeout será chamado pela primeira vez sem nenhum atraso e depois chamará novamente após o horário informado. Após a primeira execução, eles funcionam quase da mesma forma.
— Hafiz

5
A diferença é que setTimeout não se repete. Ele permite que você execute um script após um tempo definido, mas apenas uma vez. O setInterval, por outro lado, repetirá esse script, até que seja interrompido com clearTimeout ().
— Leander

648

Existe alguma diferença?

Sim. Um Timeout executa uma certa quantidade de tempo depois que setTimeout () é chamado; um intervalo executa uma certa quantidade de tempo após o intervalo anterior ser disparado.

Você notará a diferença se a função doStuff () demorar um pouco para ser executada. Por exemplo, se representarmos uma chamada para setTimeout / setInterval com ., um disparo do tempo limite / intervalo com *e da execução do código JavaScript com [-----], as linhas de tempo se parecerão com:

Timeout:

.    *  .    *  .    *  .    *  .
     [--]    [--]    [--]    [--]

Interval:

.    *    *    *    *    *    *
     [--] [--] [--] [--] [--] [--]

A próxima complicação é se um intervalo for disparado enquanto o JavaScript já estiver ocupado fazendo alguma coisa (como lidar com um intervalo anterior). Nesse caso, o intervalo é lembrado e acontece assim que o manipulador anterior termina e retorna o controle ao navegador. Por exemplo, para um processo doStuff () que às vezes é curto ([-]) e às vezes longo ([-----]):

.    *    *    •    *    •    *    *
     [-]  [-----][-][-----][-][-]  [-]

• representa um intervalo de disparo que não pôde executar seu código imediatamente e foi feito pendente.

Portanto, os intervalos tentam 'recuperar o atraso' para voltar ao cronograma. Porém, eles não enfileiram um em cima do outro: só pode haver uma execução pendente por intervalo. (Se todos estivessem na fila, o navegador ficaria com uma lista cada vez maior de execuções pendentes!)

.    *    •    •    x    •    •    x
     [------][------][------][------]

x representa um intervalo de disparo que não pôde ser executado ou ficou pendente; portanto, foi descartado.

Se sua função doStuff () normalmente demorar mais para ser executada do que o intervalo definido para ela, o navegador consumirá 100% da CPU tentando atendê-la e poderá se tornar menos responsivo.

Qual você usa e por quê?

Tempo limite encadeado fornece um slot garantido de tempo livre para o navegador; O intervalo tenta garantir que a função que está sendo executada seja executada o mais próximo possível dos horários programados, à custa da disponibilidade da interface do usuário do navegador.

Eu consideraria um intervalo para animações únicas que gostaria de ser o mais suave possível, enquanto os intervalos encadeados são mais educados para animações em andamento que ocorreriam o tempo todo enquanto a página é carregada. Para usos menos exigentes (como um atualizador trivial disparando a cada 30 segundos ou algo assim), você também pode usá-lo com segurança.

Em termos de compatibilidade do navegador, setTimeout é anterior a setInterval, mas todos os navegadores que você encontrará hoje são compatíveis com ambos. O último retardatário por muitos anos foi o IE Mobile no WinMo <6,5, mas espero que agora também esteja atrás de nós.


Mas o motivo da escolha entre Intervalo e Tempo Limite é válido mesmo para plataformas que não são de navegador, como por exemplo WebOS ou JIL?
— Vid L

2
Uma boa maneira de fazer o tempo limite acorrentados em funções anônimas: setTimeout (function () {setTimeout (arguments.callee, 10)}, 10)
— Justin Meyer

1
Em termos de compatibilidade do navegador, embora todos os navegadores forneçam os dois métodos, seu desempenho é diferente.
— unigg 7/10/10

"Mas então as chances são de que ele também não suporta mais nada que você esteja usando" tão verdadeiro
— Básico

1
drum machine por projeto de cromo usando setTimeout ("schedule ()", 0); Portanto, o navegador não terá uma pilha desnecessária quando for a guia de segundo plano do Chrome ou a falta de recursos.
— precisa

91

setInterval ()

setInterval()é um método de execução de código baseado em intervalo de tempo que possui a capacidade nativa de executar repetidamente um script especificado quando o intervalo é atingido. Ele não deve ser aninhado em sua função de retorno de chamada pelo autor do script para fazer um loop, pois ele faz um loop por padrão . Ele continuará disparando no intervalo, a menos que você ligue clearInterval().

Se você deseja fazer um loop de código para animações ou em um relógio, use setInterval().

function doStuff() {
    alert("run your code here when time interval is reached");
}
var myTimer = setInterval(doStuff, 5000);

setTimeout ()

setTimeout()é um método de execução de código baseado em tempo que executará um script apenas uma vez quando o intervalo for atingido. Ele não será repetido novamente, a menos que você o ajuste para repetir o script, aninhando o setTimeout()objeto dentro da função que ele chama para executar. Se estiver preparado para repetir, ele continuará disparando no intervalo, a menos que você ligue clearTimeout().

function doStuff() {
    alert("run your code here when time interval is reached");
}
var myTimer = setTimeout(doStuff, 5000);

Se você deseja que algo aconteça uma vez após um período especificado, use setTimeout(). Isso ocorre porque ele é executado apenas uma vez quando o intervalo especificado é atingido.


6
Boa explicação, mas observe que o OP entende a diferença básica nos exemplos que o OP forneceu. Em particular, observe que, no setTimeout()exemplo do OP , setTimeout()é chamado recursivamente , enquanto setInterval()não é.
— DavidRR

44

O setInterval facilita o cancelamento de futuras execuções do seu código. Se você usa setTimeout, deve acompanhar o ID do timer, caso deseje cancelá-lo posteriormente.

var timerId = null;
function myTimeoutFunction()
{
    doStuff();
    timerId = setTimeout(myTimeoutFunction, 1000);
}

myTimeoutFunction();

// later on...
clearTimeout(timerId);

versus

function myTimeoutFunction()
{
    doStuff();
}

myTimeoutFunction();
var timerId = setInterval(myTimeoutFunction, 1000);

// later on...
clearInterval(timerId);

35
Não vejo como você não está acompanhando a identificação do timer no caso de setInterval. É apenas retirado da função.
— Kekoa

1
Outra opção com setTimeouté, em vez de salvar o id, adicionar uma ifinstrução para definir apenas o próximo tempo limite quando alguma condição for verdadeira.
— Nnnnnn

7
Kekoa, bom argumento. Mas você precisa salvar o ID do intervalo apenas uma vez. O ID do tempo limite provavelmente está mudando a cada chamada, portanto, você deve acompanhar essas alterações. O código que deseja limpar o tempo limite deve, de alguma forma, ter acesso ao valor atual dessa variável. Além disso, é impossível limpar o tempo limite durante a execução doStuffporque o ID é inválido. No entanto, não é realmente necessário salvar os IDs de tempo limite. Em vez disso, você pode simplesmente parar de ligar setTimeout.
— Robert

4
Na minha experiência, na maioria das vezes você deseja cancelar mesmo usando setTimeout. 99% do tempo que você deseja cancelar antes que a próxima invocação ocorra, não após a conclusão da próxima.
— 111311 Kamiel Wanrooij

23

Acho o setTimeoutmétodo mais fácil de usar se você deseja cancelar o tempo limite:

function myTimeoutFunction() {
   doStuff();
   if (stillrunning) {
      setTimeout(myTimeoutFunction, 1000);
   }
}

myTimeoutFunction();

Além disso, se algo der errado na função, ele irá parar de repetir no primeiro erro, em vez de repetir o erro a cada segundo.


20

A própria diferença está em seus propósitos.

setInterval()
   -> executes a function, over and over again, at specified time intervals  

setTimeout()
   -> executes a function, once, after waiting a specified number of milliseconds

É simples assim

Detalhes mais elaborados aqui http://javascript.info/tutorial/settimeout-setinterval


7
Boa explicação concisa, mas observe que o OP entende a diferença básica nos exemplos que o OP forneceu. Em particular, observe que, no setTimeout()exemplo do OP , setTimeout()é chamado recursivamente , enquanto setInterval()não é.
— DavidRR

14

Quando você executa alguma função dentro de setInterval, que funciona mais que o tempo limite -> o navegador fica travado.

- Por exemplo, doStuff () leva 1500 seg. para ser executado e você faz: setInterval (doStuff, 1000);
1) O navegador executa doStuff (), que leva 1,5 segundos. para ser executado;
2) Após ~ 1 segundo, ele tenta executar doStuff () novamente. Mas o doStuff () anterior ainda é executado-> portanto, o navegador adiciona essa execução à fila (para executar após a conclusão da primeira).
3,4, ..) A mesma adição à fila de execução para as próximas iterações, mas doStuff () da anterior ainda está em andamento ...
Como resultado - o navegador está travado.

Para evitar esse comportamento, a melhor maneira é executar setTimeout dentro de setTimeout para emular setInterval .
Para corrigir o tempo limite entre as chamadas setTimeout, você pode usar a alternativa de autocorreção à técnica setInterval do JavaScript .


1
Não sei por que ninguém encontrou valor nesta resposta!
— Randall Vishman

9

Eu uso setTimeout.

Aparentemente, a diferença é que setTimeout chama o método uma vez, setInterval chama repetidamente.

Aqui está um bom artigo explicando a diferença: Tutorial: Temporizadores JavaScript com setTimeout e setInterval


2
Sim, eu tenho essa diferença, mas os dois pedaços de código que eu fornecidos devem, em seguida, fazer a mesma coisa ...
— Damovisa

Ummm sim ... eu teria pensado ... mas de acordo com dcaunt e sua contagem de votos, não é bem isso que acontece.
— Bravax 08/04/09

9

Seu código terá diferentes níveis de execução e, em alguns projetos, como jogos online, não é aceitável. Primeiro, o que você deve fazer para que seu código funcione com os mesmos valores internos, você deve alterar "myTimeoutFunction" para isso:

function myTimeoutFunction()
{
    setTimeout(myTimeoutFunction, 1000);
    doStuff();
}
myTimeoutFunction()

Após essa alteração, será igual a

function myTimeoutFunction()
{
    doStuff();
}
myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);

Mas você ainda não terá resultado estável, porque o JS é de thread único. Por enquanto, se o encadeamento JS estiver ocupado com algo, ele não poderá executar sua função de retorno de chamada e a execução será adiada por 2-3 ms. É você ter 60 execuções por segundo e cada vez que você tiver um atraso aleatório de 1 a 3 segundos, isso não será aceitável (após um minuto, será um atraso de cerca de 7200 ms), e posso aconselhá-lo a usar algo assim:

    function Timer(clb, timeout) {
        this.clb = clb;
        this.timeout = timeout;
        this.stopTimeout = null;
        this.precision = -1;
    }

    Timer.prototype.start = function() {
        var me = this;
        var now = new Date();
        if(me.precision === -1) {
            me.precision = now.getTime();
        }
        me.stopTimeout = setTimeout(function(){
            me.start()
        }, me.precision - now.getTime() + me.timeout);
        me.precision += me.timeout;
        me.clb();
    };

    Timer.prototype.stop = function() {
        clearTimeout(this.stopTimeout);
        this.precision = -1;
    };

    function myTimeoutFunction()
    {
        doStuff();
    }

    var timer = new Timer(myTimeoutFunction, 1000);
    timer.start();

Este código garantirá um período de execução estável. Até o encadeamento estará ocupado, e seu código será executado após 1005 ms, na próxima vez haverá um tempo limite de 995 ms e o resultado será estável.


7

Fiz um teste simples setInterval(func, milisec), porque estava curioso sobre o que acontece quando o consumo de tempo da função é maior que a duração do intervalo.

setIntervalvai geralmente agendar próxima iteração logo após o início da iteração anterior, a menos que a função ainda está em curso . Nesse caso, setIntervalaguarde até que a função termine. Assim que isso acontece, a função é acionada imediatamente novamente - não há espera para a próxima iteração de acordo com o cronograma (pois estaria em condições sem a função tempo excedido). Também não há situação com iterações paralelas em execução.

Eu testei isso no Chrome v23. Espero que seja uma implementação determinística em todos os navegadores modernos.

window.setInterval(function(start) {
    console.log('fired: ' + (new Date().getTime() - start));
    wait();
  }, 1000, new Date().getTime());

Saída do console:

fired: 1000    + ~2500 ajax call -.
fired: 3522    <------------------'
fired: 6032
fired: 8540
fired: 11048

A waitfunção é apenas uma chamada ajax síncrona auxiliar de bloqueio de encadeamento, que leva exatamente 2500 milissegundos de processamento no lado do servidor:

function wait() {
    $.ajax({
        url: "...",
        async: false
    });
}

1
"nenhuma situação com iterações paralelas em execução" - sim, isso deve ser impossível. O JavaScript do lado do cliente possui um único modelo de execução encadeada, para que nada (manipuladores de eventos etc.) aconteça ao mesmo tempo. É por isso que nada acontece (e o navegador não responde) durante a chamada ajax síncrona.
— MrWhite

O navegador responde em poucos ms entre "intervalos"? Outro evento seria acionado se estivesse pendente? (Obrigado pelos testes btw +1)
— MrWhite 29/11

1
Segundo o MDN, é considerado " uso perigoso " se a função puder ser executada por mais tempo que o intervalo. Uma setTimoutchamada recursiva é preferida.
— precisa saber é o seguinte

6

Para olhar um pouco diferente: setInterval garante que um código seja executado a cada intervalo especificado (por exemplo, 1000ms ou quanto você especificar) enquanto setTimeout define o tempo que 'espera' até que ele execute o código. E, como leva milissegundos extras para executar o código, ele adiciona até 1000ms e, portanto, o setTimeout é executado novamente em momentos inexatos (acima de 1000ms).

Por exemplo, temporizadores / contagens regressivas não são feitos com setTimeout, são feitos com setInterval, para garantir que não demore e que o código seja executado no intervalo exato especificado.


5

SetInterval e setTimeout retornam um ID de timer que você pode usar para cancelar a execução, ou seja, antes que os tempos limite sejam acionados. Para cancelar, você chama clearInterval ou clearTimeout assim:

var timeoutId = setTimeout(someFunction, 1000);
clearTimeout(timeoutId);
var intervalId = setInterval(someFunction, 1000),
clearInterval(intervalId);

Além disso, os tempos limite são cancelados automaticamente quando você sai da página ou fecha a janela do navegador.


4

Você pode validar a resposta do bobince sozinho ao executar o javascript a seguir ou verificar este JSFiddle

<div id="timeout"></div>
<div id="interval"></div>

var timeout = 0;
var interval = 0;

function doTimeout(){
    $('#timeout').html(timeout);
    timeout++;
    setTimeout(doTimeout, 1);
}

function doInterval(){
    $('#interval').html(interval);
    interval++;
}

$(function(){
    doTimeout();
    doInterval();
    setInterval(doInterval, 1);
});

3

Bem, setTimeout é melhor em uma situação, como acabei de aprender. Eu sempre uso setInterval, que me resta para executar em segundo plano por mais de meia hora. Quando voltei para essa guia, a apresentação de slides (na qual o código foi usado) estava mudando muito rapidamente, em vez de a cada 5 segundos que deveria. De fato, acontece novamente quando eu testo mais e se a culpa é do navegador ou não, não é importante, porque com setTimeout essa situação é completamente impossível.


Parece que você chamou setInterval dentro da função que estava chamando. É assim que você faz um loop com setTimeout, mas com setInterval você está criando um loop totalmente novo toda vez que é chamado.
— Stephen R


2

Apenas adicionando o que já foi dito, mas a versão setTimeout do código também alcançará o Maximum call stack sizeque impedirá seu funcionamento. Como não existe um caso básico para a função recursiva parar, você não pode executá-la para sempre.


Eu não acho que isso seja verdade. Veja aqui stackoverflow.com/questions/8058612/…
— Kevin Wheeler

-1

A diferença mais genérica entre e setInterval (expressão, duração) é que

setTimeout () executará a expressão apenas ONCE e depois dessa duração especificada.

Contudo,

setInterval () executará a expressão no INFINITE-LOOP após cada duração especificada.


-5

Eu penso SetIntervale SetTimeoutsou diferente. SetIntervalexecuta o bloco de acordo com o tempo definido enquanto SetTimeoutexecuta o bloco de código uma vez.

Experimente este conjunto de códigos após os segundos da contagem regressiva do tempo limite:

setInterval(function(e){
    alert('Ugbana Kelvin');
}, 2000);

e então tente

setTimeout(function(e){
    alert('Ugbana Kelvin');
}, 2000);

Você pode ver as diferenças por si mesmo.


Isso não responde à pergunta. settimeout () pode ser usado recursivamente para fornecer o mesmo resultado que setinterval. A questão era sobre o desempenho dessas duas opções.
— Tomas Gonzalez
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.