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 ?

Damovisa
fonte
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
tente isso jsfiddle.net/pramendra/Y4vEV #
Pramendra Gupta
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)

David Snabel-Caunt
fonte
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.

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

Haris
fonte
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);
Kamiel Wanrooij
fonte
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.

Guffa
fonte
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

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

Serg Hospodarets
fonte
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

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

degr
fonte
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
    });
}
jwaliszko
fonte
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.

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

Helgi
fonte
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);
});
Gudradain
fonte
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.

Nino
fonte
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

A diferença é óbvia no console:

insira a descrição da imagem aqui

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

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

Anshu Aditya
fonte
-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.

Ugbana Chukwujindu Kelvin
fonte
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