Uma visão geral dos web workers

Até agora, grande parte do conteúdo deste curso se concentrou em conceitos como considerações gerais sobre desempenho de HTML, dicas de recursos, otimização de vários tipos de recursos para melhorar o tempo de carregamento da página inicial e a capacidade de resposta à entrada do usuário, bem como recursos específicos de carregamento lento.

No entanto, há um aspecto do desempenho em relação ao JavaScript que ainda não foi abordado neste curso. Esse é o papel dos Web workers na melhoria da capacidade de resposta da entrada, que será abordado neste e no próximo módulo.

O JavaScript é frequentemente descrito como uma linguagem de thread único. Na prática, isso se refere à linha de execução principal, que é a única em que o navegador faz a maior parte do trabalho que você vê no navegador. Esse trabalho inclui tarefas envolvidas em coisas como scripting, alguns tipos de trabalho de renderização, análise de HTML e CSS e outros tipos de trabalho voltados ao usuário que impulsionam a experiência do usuário. Na verdade, os navegadores usam outras linhas de execução para realizar o trabalho que você, como desenvolvedor, normalmente não tem, como as linhas de execução da GPU.

Com relação ao JavaScript, geralmente você só precisa trabalhar na linha de execução principal, mas apenas por padrão. É possível registrar e usar outras linhas de execução em JavaScript. O recurso que permite o uso de várias linhas de execução no JavaScript é conhecido como API Web Workers.

Os Web workers são úteis quando há um trabalho computacionalmente caro que não pode ser executado na linha de execução principal sem gerar tarefas longas que tornam a página não responsiva. Essas tarefas certamente podem afetar a Interação com a próxima exibição (INP) do seu site. Por isso, pode ser útil saber quando você tem trabalho que pode ser feito inteiramente fora da linha de execução principal. Isso pode ajudar a criar mais espaço para outras tarefas na linha de execução principal, tornando as interações do usuário mais rápidas.

Este módulo e a demonstração subsequente que mostra um caso de uso concreto abordam os Web workers. A demonstração mostra como você pode usar um Web worker para realizar o trabalho de leitura de metadados de imagem de um arquivo JPEG fora da linha de execução principal e como retornar esses metadados para a linha de execução principal.

Como um web worker é iniciado

Um Web worker é registrado ao instanciar a classe Worker. Ao fazer isso, você especifica onde o código do worker da Web está localizado, que o navegador carrega e, em seguida, cria uma nova linha de execução para ela. A linha de execução resultante geralmente é chamada de linha de execução de worker.

const myWebWorker = new Worker('/js/my-web-worker.js');

No arquivo JavaScript do worker (my-web-worker.js, neste caso), é possível programar um código que será executado em uma linha de execução de worker separada.

Limitações do worker da Web

Ao contrário do JavaScript executado na linha de execução principal, os Web workers não têm acesso direto ao contexto window e têm acesso limitado às APIs fornecidas. Os Web workers estão sujeitos às seguintes restrições:

  • Os web workers não podem acessar diretamente o DOM.
  • Os workers da Web podem se comunicar com o contexto window por meio de um pipeline de mensagens, o que significa que eles podem acessar indiretamente o DOM de alguma forma.
  • O escopo do worker da Web é self, em vez de window.
  • O escopo do Web worker tem acesso a primitivos e construções do JavaScript, além de APIs como fetch e um número consideravelmente grande de outras APIs.

Como os workers da Web se comunicam com o window

É possível que um worker da Web se comunique com o contexto window da linha de execução principal usando um pipeline de mensagens. Esse pipeline permite transferir dados de e para a linha de execução principal e o web worker. Para enviar dados de um worker da Web para a linha de execução principal, configure um evento message no contexto do worker da Web (self).

// my-web-worker.js
self.addEventListener("message", () => {
  // Sends a message of "Hellow, window!" from the web worker:
  self.postMessage("Hello, window!");
});

Em seguida, em um script no contexto window na linha de execução principal, você pode receber a mensagem da linha de execução de worker da Web usando outro evento message:

// scripts.js

// Creates the web worker:
const myWebWorker = new Worker('/js/my-web-worker.js');

// Adds an event listener on the web worker instance that listens for messages:
myWebWorker.addEventListener("message", ({ data }) => {
  // Echoes "Hello, window!" to the console from the worker.
  console.log(data);
});

O pipeline de mensagens do Web worker é uma espécie de saída do contexto do Web worker. Com ele, é possível enviar dados do Web worker para o window e usá-los para atualizar o DOM ou realizar outras tarefas que precisam ser feitas na linha de execução principal.

teste seus conhecimentos

Em qual linha de execução um web worker é executado?

A linha de execução principal.
Tente de novo.
A própria linha de execução (também conhecida como linha de execução de worker da Web).
Correto.
A linha de execução da GPU.
Tente de novo.

O que um web worker pode acessar?

Primitivas JavaScript, como matrizes e objetos.
Correto.
Um subconjunto restrito de APIs disponíveis no contexto window, incluindo fetch.
Correto.
O contexto window, mas apenas indiretamente.
Correto.

Como um web worker pode acessar o contexto "window"?

Diretamente, referenciando membros do objeto window.
Tente de novo.
Um worker da Web não pode acessar o window de forma alguma.
Tente de novo.
Por um pipeline de mensagens facilitado pelo método postMessage no contexto do worker da Web (self).
Correto.

A seguir: um caso de uso concreto de um web worker

No próximo módulo, um caso de uso concreto de um worker da Web será detalhado e demonstrado. Nesse módulo, um worker da Web é usado para buscar um arquivo JPEG de um determinado URL e ler os metadados Exif dele em um worker da Web. Esses dados são então enviados de volta à linha de execução principal para serem exibidos ao usuário.