Usando o Worklet de Animação

Georgy Marchuk Blocked Desbloquear Seguir Seguindo 10 de janeiro

O novo Animation Worklet de Houdini faz parte de uma iniciativa maior para trazer animações nativas para a web, que também inclui a API de animação da web (WAAPI).

Ao contrário de outros esforços que temos visto ultimamente, o Animation Worklet traz algumas vantagens para o jogo que nós não conseguimos no passado. Este artigo explica o que há de novo com Worklets e onde ele pode bater qualquer código atual ou biblioteca de animação.

Simplificando, o Animation Worklet (em contraste com outras técnicas de animação, como a transição de CSS , CSS Animation com keyframes ou WAAPI ), não precisa ser baseado em tempo. Isso nos permite basear nossa animação na entrada do usuário, como a rolagem, algum estado anterior ou qualquer outra coisa que possamos acessar com JavaScript.

O Worklet, sendo um trabalhador leve, é executado independentemente do thread principal do JavaScript e visa descarregar o processamento difícil ou o trabalho frequente fora do thread principal, portanto, em um mundo ideal, quaisquer falhas ou atrasos no thread principal não precisam resultar em um atraso da animação na mesma página. Da mesma forma, qualquer afunilamento na animação não resulta automaticamente na redução da experiência geral da página.

A sintaxe

Vamos mergulhar no código e ver o que é tudo isso. O uso do Worklet requer várias etapas de configuração.

Pré-requisitos

Embora o Worklet de animação seja um novo recurso e o estado da especificação do Worklet seja um "rascunho de trabalho", você pode tentar ativá-lo agora no Chrome com o sinalizador de recursos da Plataforma da Web experimental. Eu recomendo que você faça isso se você estiver indo para experimentar as demos neste artigo.

Verificação de suporte

Embora não seja recomendado usar o Worklet na produção, ainda é possível usar um Worklet com fallback. Verificar o suporte de Worklets ajudará com isso. Também impedirá quebrar toda a execução do JavaScript.

Animador de worklet

O animador, sendo um trabalhador leve e servindo como uma extensão da funcionalidade nativa dos navegadores, precisa ser registrado como tal. O modo como é registrado é confuso no início, mas é bastante comum nos recursos mais recentes dos navegadores, como os Service Workers . O animador é carregado de um arquivo separado usando o método CSS.animationWorklet.addModule () . O método aceita o caminho para o arquivo do animador e retorna um Promise para nos dar um retorno de chamada para quando nosso animador for carregado.

O código real para registrar o animador é bastante simples usando a função registerAnimator. A função aceita dois argumentos, o nome do animador do Worklet e o construtor Worklet em uma forma de classe.

A classe pode ter métodos como qualquer outra classe, mas o método principal em que estamos interessados é o método animate , que é usado para refletir as mudanças no tempo atual da sua animação. O método animate é chamado em cada quadro e, ao contrário de requestAnimationFrame , o método de animação é chamado com a maior frequência possível limitado apenas pelo hardware (o valor padrão de FPS que o requestAnimationFrame está tentando alcançar é 60, enquanto muitos monitores têm taxas de quadros mais altas).

O método aceita o currentTime e o objeto de efeito e é usado para aplicar as alterações de um currentTime ao efeito. currentTime é o valor passado em um Worklet pela linha do tempo, que, como mencionei anteriormente, não precisa ser representado por uma hora quando se trata dos Worklets. Mais sobre isso depois.

Por enquanto, vamos começar com um exemplo simples de deixar a linha do tempo passar e atribuir o mesmo valor ao objeto de efeito como effect.localTime . O valor da propriedade localTime é então aplicado à animação do Worklet descrita adiante.

O Worklet

Assim que tivermos toda essa configuração, podemos usar o animador para nossa animação no código padrão. A animação é criada com um construtor WorkletAnimation que aceita três argumentos – o nome do animador, a instância de um KeyframeEffect e a linha do tempo. Uma quarta opção na forma de um objeto seria passada para o construtor de classe registerAnimator.

A configuração acima irá criar uma animação simples e infinita de uma caixa rotativa. Ao estender um pouco mais o objeto de quadro-chave, conseguiremos uma caixa fazendo rolagens de barril.

Observe que as demonstrações foram modificadas para usar blobs em vez de um arquivo separado, para trabalhar em um Codepen. Você pode acessar o repositório com as demos originais no GitHub e Páginas GitHub .

Você notará aqui que a sintaxe é direta e as opções são bastante autodescritivas e fáceis de usar. Enquanto isso é legal, não há nada aqui que não possamos fazer com uma simples animação CSS e keyframes.

Animador como uma função matemática

Então, vamos tentar algo mais complexo. O animador e seu método de animação podem ser qualquer coisa que queremos que seja. Isso significa que podemos aplicar funções matemáticas à nossa linha do tempo…

… Ou alguma lógica personalizada, como arredondar o número da hora atual da linha do tempo.

Essa manipulação dos valores atuais da linha do tempo nos fornece uma nova maneira de executar animações. Pense nisso como aliviar os esteróides. Em vez de ter três ou mais pontos para descrever a atenuação como uma curva, podemos usar o JavaScript para apenas programar qualquer comportamento que desejemos com base no valor da linha de tempo atual.

Ao modificar o animador com lógica personalizada, é importante ter em mente que effect.localTime é usado como a hora atual da linha do tempo da animação na animação do Worklet. Isso significa que quaisquer números negativos ou cálculos retornando NaN não podem ser processados na animação. Naturalmente, nosso código deve refletir isso e implementar precauções.

O pergaminho

O Animation Worklet foi projetado especificamente para funcionar com eventos como o pergaminho. É simples basear a linha de tempo da animação na rolagem, em vez de no tempo. Tudo o que precisamos fazer é usar um construtor ScrollTimeline em vez do clássico document.timeline .

Há alguns fatos sobre os navegadores que precisamos saber para entender por que vale a pena usar o Worklet de animação. Em alguns casos, o uso do Worklet de Animação pode melhorar drasticamente o desempenho.

Tópicos do navegador

Os navegadores são multithreaded. Na verdade, eles foram por um tempo. No entanto, isso não significa automaticamente que todos os nossos núcleos de CPU e a GPU processam o aplicativo da web quando ele está em execução. Cada navegador, na verdade, adota uma abordagem ligeiramente diferente ao implementar o multithreading.

O Chrome se concentra em separar as guias do navegador em processos isolados. Isso permite que cada processo / guia seja executado em um núcleo separado e, de alguma forma, utilize toda a CPU quando estiver funcionando. Também tem a vantagem de ter apenas uma aba sem resposta quando algo dá errado e o processo fica preso.

No entanto, cada processo está executando todas as partes que normalmente poderiam ser reutilizadas pelas instâncias da página da web. Isso afeta drasticamente a quantidade de memória que o Chrome precisa executar, o que afeta a vida útil da bateria. Mas quem estiver lendo isso e usando o Chrome provavelmente já sabe sobre esse problema.

O Firefox usa uma abordagem diferente. Ele executa no máximo quatro processos para todas as guias. Cada guia é atribuída a um dos processos para ser responsável pela guia. Com a atualização do Quantum, é possível processar certas tarefas para uma guia em vários segmentos. Mas isso é limitado a tarefas que podem ser separadas em segmentos paralelos, como o processamento de CSS de sites.

Em suma, os navegadores são um pouco multithread e tentam obter o máximo possível de separação do processo. Existe uma certa limitação para todos os navegadores.

Loop de eventos

O Event Loop é algo realmente essencial para os navegadores e, no entanto, muitas pessoas não sabem disso. O Event Loop é responsável por agendar e processar as tarefas que acontecem na guia. Não importa qual, a tarefa acaba na fila e, a partir daí, é executada quando é hora, mesmo para o código assíncrono. É por isso que o thread principal do JavaScript é muito difícil de separar em vários threads, porque as coisas são projetadas para acontecer uma após a outra, não em paralelo.

Chamadas de função freqüente

Não há nada de errado em executar tarefas de maneira serial em um encadeamento até que ocorra uma chamada de função freqüente que possa bloquear o encadeamento. Um exemplo perfeito desse evento é o pergaminho.

O evento de rolagem é algo muito usado no aplicativo – seja para mostrar / ocultar algum tipo de menu ou simplesmente transformar algumas partes decorativas da Web com base na distância percorrida pelo usuário. Alguns até diriam que o pergaminho é a principal interação do usuário e muitos aplicativos da web, como Facebook, Instagram ou Twitter, são baseados principalmente no usuário percorrendo o conteúdo.

Dito isto, qualquer atraso desta interação pode ser muito irritante. Embora seja um evento que usamos na web com bastante frequência, é incrivelmente fácil desorganizar o desempenho. A execução do nosso código no pergaminho pode ter uma parte drástica do nosso thread principal do navegador, especialmente quando se trata de código caro, como animação, causando uma nova renderização.

Na verdade, alguns navegadores até começaram a implementar os listeners de rolagem como passivos por padrão (para que o navegador não precise aguardar a execução para ver se o event.preventDefault () aparece no código), para tornar o código mais otimizado, a menos que especificado de outra forma.

É aí que o Worklet Animation vem para o resgate. Como um trabalho de descarregamento de funcionalidade nativa para um encadeamento separado, um navegador pode fazer todos os cálculos necessários em um processo separado e voltar apenas às instruções de renderização. Isso é algo que não era possível antes e poderia melhorar drasticamente a animação baseada em rolagem. Isto é, obviamente, assumindo que a implementação do navegador fará a otimização corretamente para nós.

O Estado

registerAnimator é uma classe, e vem com todas as possibilidades que a classe traz (e até algumas inesperadas descritas mais adiante). A classe pode agir de forma independente, ter um escopo, salvar algum tipo de estado, ser estendida e muito mais.

Isso significa que a animação não pode apenas espelhar a hora atual na linha do tempo, mas também agir com base no comportamento anterior ou em algum estado que tenhamos salvo anteriormente. O exemplo a seguir altera a cor da caixa com base na direção da rolagem. A direção é detectada salvando o estado anterior da linha de tempo de rolagem e definindo manualmente o estado da linha do tempo para o início / fim com base na direção para afetar o plano de fundo da caixa.

Estado de conservação

A separação do código do Worklet em várias partes tem vários motivos. Uma razão é separar em segmentos independentes. Novamente semelhante aos Service Workers, o Worklet de Animação pode ser encerrado quando não utilizado e pode salvar o estado em vários recarregamentos. Atualmente, teríamos que usar alguma outra tecnologia (como armazenamento local) para obter o mesmo efeito.

Infelizmente, até o Chrome atualmente não suporta salvar o estado, ou a documentação simplesmente não reflete as alterações recentes da API. Mas, dado que o recurso é experimental, não há nada de errado nisso.

Conclusão

O Animation Worklet é uma adição promissora para a família de animação nativa. Seu foco na separação da carga de trabalho em outros segmentos é definitivamente uma boa prática que veremos muito mais nas futuras APIs implementadas.

Apesar da funcionalidade pura, ainda há algumas partes em torno desta tecnologia que não fazem muito sentido. Por exemplo, acho que a convenção de nomenclatura sobre a opção timerange do construtor ScrollTimeline confuso. Não tem nada a ver com o tempo.

O worklet ainda é claramente um trabalho em andamento, baseado em muitos fatores, como a preservação do estado, que não funciona como esperado (ou melhor, a documentação não indica o estado atual da API).

Outra coisa que vale a pena mencionar é a abertura da API, como se ela fosse construída para ser estendida. Você pode ver isso em um objeto CSS.animationWorklet , onde o único método atualmente implementado é o método addModule usado neste tutorial. O fato de que aplicar a hora atual na classe do animador é feito atribuindo um valor ao effect.localTime sugere mais algumas funcionalidades para o objeto de efeito que ainda não foi implementado.

As novas APIs do Worklet incluem coisas como PaintWorklet, AudioWorklet ou LayoutWorklet, que definitivamente trarão algumas coisas mais interessantes, cada uma com foco na solução de uma tarefa específica. Mas vamos deixar isso para outra hora.

Plug: LogRocket , um DVR para aplicativos da web

https://logrocket.com/signup/

LogRocket é uma ferramenta de registro de front-end que permite que você repita problemas como se eles tivessem ocorrido em seu próprio navegador. Em vez de adivinhar por que os erros ocorrem ou solicitar aos usuários capturas de tela e log dumps, o LogRocket permite que você repita a sessão para entender rapidamente o que deu errado. Ele funciona perfeitamente com qualquer aplicativo, independentemente do framework, e possui plugins para registrar o contexto adicional do Redux, Vuex e @ ngrx / store.

Além de registrar as ações e o estado do Redux, o LogRocket registra logs do console, erros de JavaScript, rastreamentos de pilha, solicitações / respostas de rede com cabeçalhos + corpos, metadados do navegador e logs personalizados. Ele também instrumenta o DOM para gravar o HTML e CSS na página, recriando vídeos com pixels perfeitos até mesmo dos aplicativos de página única mais complexos.

Experimente Grátis.