Eu tenho um setInterval
código de execução 30 vezes por segundo. Isso funciona muito bem, no entanto, quando seleciono outra guia (para que a guia com o meu código fique inativa), ela setInterval
é configurada para um estado inativo por algum motivo.
Fiz este caso de teste simplificado ( http://jsfiddle.net/7f6DX/3/ ):
var $div = $('div');
var a = 0;
setInterval(function() {
a++;
$div.css("left", a)
}, 1000 / 30);
Se você executar esse código e alternar para outra guia, aguarde alguns segundos e volte, a animação continuará no ponto em que você mudou para a outra guia. Portanto, a animação não está sendo executada 30 vezes por segundo, caso a guia esteja inativa. Isso pode ser confirmado contando a quantidade de vezes que a setInterval
função é chamada a cada segundo - isso não será 30, mas apenas 1 ou 2 se a guia estiver inativa.
Eu acho que isso é feito por design, a fim de melhorar o desempenho, mas existe alguma maneira de desativar esse comportamento? Na verdade, é uma desvantagem no meu cenário.
fonte
Date
objeto para realmente ver que horas passaram.Date
. Assim, quando os intervalos não disparam rapidamente (por esse ou outros motivos), a animação fica mais instável, não mais lenta.Respostas:
Na maioria dos navegadores, as guias inativas têm execução de baixa prioridade e isso pode afetar os timers do JavaScript.
Se os valores da sua transição foram calculados usando o tempo real decorrido entre os quadros, em vez de incrementos fixos em cada intervalo, você não apenas contorna esse problema, mas também pode obter uma animação mais nítida usando requestAnimationFrame pois ele pode chegar a 60 fps se o processador não estiver muito ocupado.
Aqui está um exemplo de baunilha JavaScript de uma transição de propriedade animada usando
requestAnimationFrame
:Para tarefas em segundo plano (não relacionadas à interface do usuário)
Comentário @UpTheCreek:
Se você tiver tarefas em segundo plano que precisem ser executadas com precisão em determinados intervalos, poderá usar HTML5 Web Workers . Dê uma olhada na resposta da Möhre abaixo para obter mais detalhes ...
CSS vs JS "animações"
Esse problema e muitos outros poderiam ser evitados usando transições / animações CSS em vez de animações baseadas em JavaScript, o que adiciona uma sobrecarga considerável. Eu recomendo este plugin jQuery que permite que você tire proveito das transições CSS, assim como os
animate()
métodos.fonte
before = now;
para obter o tempo decorrido desde o início, em vez do final da chamada anterior. Isso geralmente é o que você deseja ao animar as coisas. Como é agora, se uma execução da função de intervalo demorar 15ms,elapsedTime
dará 35ms (em vez de 50ms, que é o intervalo) da próxima vez que for chamada (quando a guia estiver ativa).Corri para o mesmo problema com desbotamento de áudio e HTML5 player. Ficou preso quando a guia ficou inativa. Então, descobri que um WebWorker tem permissão para usar intervalos / tempos limite sem limitação. Eu o uso para postar "ticks" no javascript principal.
Código WebWorkers:
Javascript principal:
fonte
Existe uma solução para usar Web Workers (como mencionado anteriormente), porque eles são executados em processo separado e não são mais lentos
Eu escrevi um pequeno script que pode ser usado sem alterações no seu código - ele simplesmente substitui as funções setTimeout, clearTimeout, setInterval, clearInterval.
Basta incluí-lo antes de todo o seu código.
mais informações aqui
fonte
Apenas faça o seguinte:
As guias inativas do navegador armazenam em buffer algumas das funções
setInterval
ousetTimeout
.stop(true,true)
interromperá todos os eventos em buffer e executará imediatamente apenas a última animação.O
window.setTimeout()
método agora prende para enviar não mais que um tempo limite por segundo em guias inativas. Além disso, ele agora fixa os tempos limite aninhados ao menor valor permitido pela especificação HTML5: 4 ms (em vez dos 10 ms nos quais costumava fixar).fonte
Eu acho que um melhor entendimento sobre esse problema está neste exemplo: http://jsfiddle.net/TAHDb/
Estou fazendo uma coisa simples aqui:
Tenha um intervalo de 1 segundo e sempre oculte o primeiro período, mova-o para o último e mostre o segundo período.
Se você permanecer na página, ele funcionará como deveria. Mas se você esconder a guia por alguns segundos, quando voltar, verá uma coisa estranha.
É como todos os eventos que não ocorreram durante o período em que você estava inativo agora ocorrerão todos de uma vez. então, por alguns segundos, você terá como X eventos. eles são tão rápidos que é possível ver todos os 6 intervalos de uma só vez.
Por isso, o costuras cromadas atrasa apenas os eventos; portanto, quando você voltar, todos os eventos ocorrerão, mas todos de uma vez ...
Uma aplicação prática ocorreu neste momento para uma apresentação de slides simples. Imagine os números como Imagens, e se o usuário ficar com a guia oculta quando ele voltar, ele verá todas as imagens flutuando, Totalmente mesed.
Para corrigir isso, use o stop (true, true) como o pimvdb disse. Isso limpará a fila de eventos.
fonte
requestAnimationFrame
ao jQuery usado. Por causa de algumas peculiaridades que tinha (como esta), eles a removeram. Na versão 1.7, você não vê esse comportamento. jsfiddle.net/TAHDb/1 . Como o intervalo é de uma vez por segundo, isso realmente não afeta o problema que publiquei, pois o máximo de guias inativas também é uma vez por segundo - de modo que não faz diferença.Para mim, não é importante reproduzir áudio em segundo plano, como acontece com outros aqui, meu problema era que eu tinha algumas animações e elas agiam como loucas quando você estava em outras abas e voltando para elas. Minha solução foi colocar essas animações dentro se isso está impedindo a guia inativa :
graças a isso, minha animação estava sendo executada apenas se a guia estivesse ativa. Espero que isso ajude alguém com o meu caso.
fonte
setInterval(() => !document.hidden && myfunc(), 1000)
e funciona perfeitamente #Ambos
setInterval
erequestAnimationFrame
não funcionam quando a guia está inativa ou funciona, mas não nos períodos certos. Uma solução é usar outra fonte para eventos de tempo. Por exemplo, soquetes da Web ou trabalhadores da Web são duas fontes de eventos que funcionam bem enquanto a guia está inativa. Portanto, não é necessário mover todo o seu código para um trabalhador da Web, basta usar o trabalhador como uma fonte de evento de tempo:.
jsfiddle link desta amostra.
fonte
Fortemente influenciado pela biblioteca de Ruslan Tushov, criei minha própria pequena biblioteca . Basta adicionar o script no
<head>
e ele será corrigidosetInterval
esetTimeout
com os que forem usadosWebWorker
.fonte
A reprodução de um arquivo de áudio garante o desempenho completo do Javascript por enquanto
Para mim, era a solução mais simples e menos invasiva - além de tocar um som fraco / quase vazio, não há outros efeitos colaterais em potencial
Você pode encontrar os detalhes aqui: https://stackoverflow.com/a/51191818/914546
(A partir de outras respostas, vejo que algumas pessoas usam propriedades diferentes da tag Audio, me pergunto se é possível usar a tag Audio para obter desempenho total, sem realmente reproduzir algo)
fonte
Nota: esta solução não é adequada se você gosta que seu intervalo funcione em segundo plano, por exemplo, reproduzindo áudio ou ... mas se você está confuso, por exemplo, sobre sua animação não funcionar corretamente ao retornar à sua página (guia), é uma boa solução
Existem várias maneiras de atingir esse objetivo, talvez o "WebWorkers" seja o mais padrão, mas certamente não é o mais fácil e prático, especialmente se você não tiver tempo suficiente, tente o seguinte:
► CONCEITO BÁSICO:
1- crie um nome para o seu intervalo (ou animação) e defina seu intervalo (animação), para que funcione quando o usuário abrir sua página pela primeira vez:
var interval_id = setInterval(your_func, 3000);
2 por
$(window).focus(function() {});
e$(window).blur(function() {});
você podeclearInterval(interval_id)
sempre que o navegador (guia) for desativado e executar novamente o intervalo (animação) sempre que o navegador (guia) ativará novamente porinterval_id = setInterval();
►Código do exemplo:
fonte
É uma pergunta bastante antiga, mas encontrei o mesmo problema.
Se você executa sua web no chrome, pode ler esta postagem Guias de plano de fundo no Chrome 57 .
Basicamente, o cronômetro de intervalo pode ser executado se não ficar sem o orçamento do cronômetro.
O consumo do orçamento é baseado no uso do tempo da CPU da tarefa dentro do cronômetro.
Com base no meu cenário, eu desenho vídeo para tela e transporte para o WebRTC.
A conexão de vídeo webrtc continuaria atualizando até a guia está inativa.
No entanto, você deve usar em
setInterval
vez derequestAnimationFrame
.embora não seja recomendado para renderização da interface do usuário.
Seria melhor ouvir
visibilityChange
eventos e alterar o mecanismo de acordo.Além disso, você pode tentar o @ kaan-soral e deve funcionar com base na documentação.
fonte
Aqui está a minha solução aproximada
fonte
postMessageHandler
chama seu próprio evento que está manipulando, com um loop infinito que não está bloqueando a interface do usuário. E enquanto faz um loop infinito, verifica com cada manipulação de evento se existe uma função de tempo limite ou intervalo a ser executada.Consegui chamar minha função de retorno de chamada no mínimo 250ms usando a tag de áudio e manipulando seu evento ontimeupdate. É chamado 3-4 vezes em um segundo. É melhor que um segundo set de atraso
fonte