JavaScript e mais: 4 abordagens criativas para medir o tempo em navegadores

O autor do artigo, cuja tradução estamos publicando hoje, decidiu falar sobre várias maneiras incomuns de medir o tempo nos navegadores. Para usá-los, você precisará acessar várias APIs usadas no desenvolvimento da Web, portanto elas não são adequadas para a plataforma Node.js. É verdade que, se alguém precisar de uma maneira incomum de medir o tempo no Node.js, acreditamos que, depois de ler este material, ele poderá ter algumas idéias sobre esse assunto.



Usando um loop síncrono infinito em um trabalhador da Web (não em um trabalhador de serviço)


Como os trabalhadores da Web são essencialmente threads em execução em um navegador da Web, eles podem executar loops sem fim, sem correr o risco de bloquear o thread principal. Isso permite que você trabalhe com períodos de tempo cuja duração é menor que um milissegundo. Essa precisão é especialmente adequada para os casos em que um trabalhador precisa tomar decisões altamente dependentes do tempo. A adoção dessas decisões pode (com um nível muito alto de precisão) ser relatada ao fluxo principal. Por exemplo, você pode derivar algo no caso em que o número de microssegundos que passaram desde que um determinado evento é representado por um número primo. Para trabalhar com precisão de microssegundos ao longo do tempo, você pode usar o método performance.now .

VantVantagens


  1. Precisão alcançável expressa em microssegundos.
  2. .
  3. , , . - .
  4. . , setInterval, terminate , . MDN : « terminate() Worker . , ».


  1. Mesmo que esse método permita trabalhar com intervalos de tempo inferiores a um milissegundo, o envio de mensagens para o thread principal funciona de forma assíncrona. Ou seja, é impossível executar determinadas ações no encadeamento principal com a mesma precisão com que o trabalhador decide que essas ações precisam ser executadas.
  2. Esse método carrega totalmente o fluxo, o que pode levar ao aumento do consumo de bateria nos telefones.
  3. Este método requer o suporte de trabalhadores da Web.
  4. Um loop infinito em um trabalhador da Web não pausa se a guia associada a ele estiver inativa.

Exemplo em Codesandbox

Usando animações CSS para eventos relacionados ao tempo (em particular - animationiteration)


Este método envolve a criação de um elemento com animação sem fim. Aqui você pode tentar usar o elemento div, mas devo dizer que, conforme observado no parágrafo 2 da lista de deficiências desse método, divé melhor não usar elementos para esses fins. Portanto, se tivermos um elemento com animação infinita, poderemos assinar o evento animationiteratione receber notificações nos momentos em que o intervalo expirar animation-duration.

VantVantagens


  1. Pausar automaticamente se a guia do navegador ficar inativa. Nesse caso, o evento de interesse para nós simplesmente não ocorre. Portanto, você não precisa se preocupar em resolver o problema de processar muitos eventos acumulados durante o tempo em que a guia estava inativa e depois ativada.
  2. div DOM. , React-, , . div .
  3. , , . — :

    .addEventListener("animationiteration", fun).
  4. animation-delay.


  1. . , , .
  2. Dependência no DOM e CSSOM. Outras regras de CSS podem afetar aquelas que descrevem a animação. Portanto, aconselho que você crie uma organização de timer para algum tipo de tag arbitrariamente nomeado anteriormente inexistente como <just-a-timer-element></<just-a-timer-element>. Talvez - vale a pena criar um elemento personalizado, dentro do qual o código de animação CSS está oculto? (todas essas são idéias bastante controversas, na verdade).
  3. Este método não funciona se o elemento tiver um estilo display: none;.
  4. Imprecisão. De acordo com meus testes, a precisão da contagem regressiva pode ser de cerca de 1 ms. Você, para descobrir exatamente como isso funciona para você, pode experimentar um exemplo, um link ao qual é fornecido abaixo.

Exemplo em Codesandbox

Usando a tag svg (animações SMIL)


Dê uma olhada no seguinte elemento SVG:

<svg>
  <rect>
    <animate
      attributeName="rx"
      values="0;1"
      dur="1s"
      repeatCount="indefinite"
    />
  </rect>
</svg>

Se você usar o seguinte código : animate.addEventListener('repeat', fun), a função funserá chamada a cada dursegundo. No nosso caso, a cada segundo.

VantVantagens


  1. Este método funciona mesmo que um estilo seja atribuído ao elemento SVG display: none;.
  2. A contagem regressiva para automaticamente quando o elemento SVG é removido do DOM.
  3. A geração de eventos não inicia até que a página esteja totalmente carregada.
  4. O "temporizador" é automaticamente pausado se a guia se tornar inativa.

▍ Desvantagens


  1. Como no caso de contar intervalos de tempo usando animação CSS, a aplicação desse método pode parecer incompreensível para outros programadores.
  2. Dependência no DOM e CSSOM. Ou seja - aqui temos os mesmos recursos indesejáveis ​​que já foram descritos para o método de contagem de tempo usando animação CSS. Ou seja - a possibilidade de interrupção do "timer" devido a outras regras CSS.
  3. Não é suportado no IE e Edge (até que o navegador seja transferido da Microsoft para o Chromium).
  4. Imprecisão. De acordo com meus testes, os desvios desse cronômetro do método mais preciso podem ser impressionantes 15 milissegundos. Você mesmo pode verificar isso experimentando o exemplo, cujo link é fornecido abaixo.
  5. A contagem regressiva não inicia até que a página esteja totalmente carregada. É verdade que esse "menos" deste método pode se tornar um "mais" em algumas situações.

Exemplo em Codesandbox

Usando a API de animações da Web


A API de animações da Web permite animar elementos DOM usando o código JavaScript.

O interessante é que você pode até animar elementos não montados! Isso fornece acesso aos mecanismos de tempo disponíveis em JavaScript puro (e na API da Web).

Aqui está uma implementação alternativa setTimeout:

function ownSetTimeout(callback, duration) {
  const div = document.createElement('div');

  const keyframes = new KeyframeEffect(div, [], { duration, iterations: 1 });

  const animation = new Animation(
    keyframes,
    document.timeline
  );

  animation.play();

  animation.addEventListener('finish', () => {
    callback();
  });
}

Ordenadamente, certo?

VantVantagens


  1. Uma solução independente que não requer interação com o DOM.
  2. Um programador não familiarizado com essa abordagem entenderá facilmente o significado do código correspondente.
  3. "Timer" pausa em uma guia inativa.

▍ Desvantagens


  1. API de animações da Web - a tecnologia ainda é experimental. Não use na produção.
  2. Suporte de navegador muito ruim. É provável que esse método funcione apenas no Chromium.
  3. Com todas as vantagens desta solução, no entanto, pode parecer para alguém longe de ser intuitivo.
  4. O fato de o "cronômetro" estar pausado em uma guia inativa pode acabar sendo menos desta solução se for usada como alternativa setTimeout.
  5. Este método não pode ser usado para contar intervalos. Somente um evento está disponível para o programador onfinish.
  6. Baixa precisão. De acordo com minhas experiências, o erro pode facilmente ser de ± 5 milissegundos.

→  Exemplo em Codesandbox

Bônus


Para trabalhar com o tempo, você pode usar a API de áudio da Web. Essa é outra ótima maneira de trabalhar com precisão com intervalos e atrasos. Aqui está um ótimo artigo sobre isso.

Sumário


Entendo que as técnicas de trabalhar com o tempo que listei aqui podem se beneficiar longe de tudo. Mas não pude deixar de escrever este artigo, porque sempre pensei nisso setTimeoute setInterval- essas são as únicas maneiras de trabalhar de forma assíncrona com determinados períodos de tempo. Mas, na realidade, como se viu, isso está longe de tudo. Quem sabe, talvez alguém precise lidar com algumas restrições incomuns ao trabalhar em um determinado projeto, com algumas condições especiais em que os métodos de trabalho destacados aqui podem ser úteis ao longo do tempo.

Queridos leitores! Em que situações você acha que as abordagens baseadas no tempo descritas aqui podem ser úteis?


All Articles