Web Worker com Protobuf (Protocol Buffers)

Melhorando performance no seu frontend

Rebeca Lopes
6 min readNov 9, 2022

Quando falamos sobre desenvolvimento frontend, temos que primeiro entender como funciona a linguagem javascript e seus conceitos principais. Um dos conceitos mais importantas, porém muitas vezes esquecido, consiste em saber que Javascript não é uma linguagem multi thread, mas silgle thread.

Single Thread

Vamos entender melhor o que é o conceito de uma única thread. Conceitualmente, consiste que tudo que você programa em JS utiliza apenas uma thread do seu PC. Então quando você faz aquelas requisições sincronas, ou quando você modifica varios elementos na tela, e tem a impressão de que tudo está acontecendo ao mesmo tempo, e em ocupando varias threads do seu computador, na verdade não está.

Para entender melhor vamos ver um esquema de como isso funciona em JS

Em Javascript temos o conceito de Event Loop, que nada mais é um processo que fica rodando constantemente observando se existe algum código para ser executado, seja manipulação no DOM, request de API, etc, caso não tenha, ele olha então a Callback Queue, uma fila de espera para instruções assíncronas, e ai move esses processos para a Call Stack , que é a pilha ordenada de chamdas de função. Note que as chamdas seguem uma ordem LIFO: o último que entra é o primeiro que sai. Dessa forma não temos nativamente em javascript uma forma de executar funções paralelamente, utilizando mais de uma thread. Tudo é feito em uma única thread.

Problemas Single Thread

Você pode pensar qual problema isso pode trazer para o frontend? Conforme crescemos nossos processos, por exemplo, manipulação de dados volumosos, isso pode gerar alguns gargalos de performance, tendo em mente que tudo está em uma única thread, os processos podem gargalar e não será culpa do backend. E é ai que web workers pode te ajudar a melhorar a performance.

Web Worker

Então o que é um web worker? Segundo a documentação do Mozzila:

Web Workers são mecanismos que permitem que uma operação de um dado script seja executado em uma thread diferente da thread principal da aplicação Web. Permitindo que cálculos laboriosos sejam processados sem que ocorra bloqueio da thread principal (geralmente associado à interface).”

Observe bem o conceito e o que web worker pode resolver. Basicamente é o que foi citado neste artigo: manipular dados volumosos via frontend.

Outros usos:

  1. Formatação de texto em tempo real, verificação ortográfica e realce de sintaxe
  2. Fórmulas matemáticas complicadas, como encontrar o maior número primo
  3. Processando grandes conjuntos de dados JSON
  4. Processar/desenhar/filtrar várias imagens com canvas

Vejamos como funciona na teoria:

Básicamente temos a main thread, onde já sabemos que tudo é processado(DOM, request, promises, etc), e temos outra thread, que é o worker, ou várias outras threads. A forma que a thread principal e as outras se comunicam é por meio de mensagens. Tanto a Main thread escuta e envia mensagem, como as threads secundárias. Dessa forma podemos paralelizarmos outra threads e fazer o que quisermos nela, sem precisar que a main principal fique “travada” aguardando a fila de processos ser executada.

Claro que nem tudo são flores, temos alguns pontos a ser ponderados no uso de web workers:

  • Limitações de APIs do browser: não conseguimos alterar o DOM em um worker
  • Comunicação através de postMessage utilizando Strutured Cloning: nesse algoritimo, o dado que você estiver manipulando na thread principal será literalmente clonado (CTRL + C/CTRL +V) no worker. Portando, na mémoria do computador teremos o apontamento do mesmo objeto repetido.

E é nessa segunda limitação que podemos usar outras abordagens combinadas com web worker.

Protobuf

Vamos ver agora como podemos processar dados de forma muito mais rápida sem ter que usar Strutured Cloning. O que é Protobuf?

Protocol Buffers é um método de serialização de dados estruturados. É útil no desenvolvimento de programas que se comunicam uns com os outros ou para armazenar dados.”

Foi criado pela Google, e atende muito bem não somente web worker, mas neste artigo vou trazer para esse caso.

Para utilizar Protobuf tenha em mente que ele utiliza o conceito de transferables, que nada mais é do que buffers, não somente isso, utiliza também definição de schemas para seu objeto de dados.

Em comparação com o algoritimo de Strutured Cloning, transferables é muito mais rápido e processo muito mais dados

Definindo schemas com Protobuf

Para trabalharmos com Protobuf, é preciso instalar a lib correspondente para linguagem respectiva. No caso, vou mostrar com a lib pbf-loader. Após instalarmos já conseguimos criar o schema.

Criarmos o arquivo album.proto

Na linha 1, definimos quel a syntax proto que usaremos (2 ou 3), algumas coisa mudam de uma syntax para outra. A partir da linha 3 defino o schema do objeto Album que será o response do minha requisição. Defino que todos são requerid e o tipo de dado (int32, string).

Na linha onze, faço que o Album seja um dado que será reptido, portanto será um array de objetos.

Utilizando Protobuf com web workers

O exemplo será feito em Vue2, mas a lǵica pode ser replica em outras linguagens e frameworks javascript.

Primeiro importamos a lib, e depois o Schema que foi definido.

A represetação dos dados na linha 29, segue a representação de dados bufferizados, como na API nativa Uint8Array(matriz de inteiros sem sinal de 8 bits). Por isso, lidar transfarebles é tão mais rápido.

Observe que realizamos o fetch na API, mas não vamos fazer qualquer manipulação em nossa thread princial, deixaremos as manipulações para o worker.

No worker também importamos o schema definido. Ao recebermos a mensagem da main thread, com os dados JSON que vamos manipular, simulamos como se estivessemos fazendo calculos matemáticos complexos, no examplo fiz apenas soma e encontrar numeros pares em uma base de dados com 5000 itens. Após fazermos os cáculos enviamos de volta para main thread, dessa forma a thread principal fica livre para fazermos manipulações no DOM, outros request, seja o que for, sem precisarmos bloquear a interface para o usuário. E após termos o retorno desses dados podemos exibir na tela, por exemplo, ou fazer outra manipulação mais simples.

Conclusão

Sendo bem sincera, a aplicabilidade de web worker depende muito do que você precisa fazer. Acredito que se não for para manipularmos dados muito grandes, desenho de canvas fracionado, cálculos matemáticos complexos, tratamento de dados volumosos em real time, não faz sentido. A principio utilizar web worker puro, pode ajudar dependendo do caso. Mas se o volume de dados crescer demais, considere utilizar Protobuf para processar mais dados em menos tempo.

Referências:

--

--

Rebeca Lopes

Frontend developer at Beta Learning. Currently works with technologies such as Javascript, CSS, VueJS, NuxtJS and studies others such as ReactJS and NextJS