Colocando workers para trabalhar com HTML5

Olá pessoal, tudo certo!?

O post de hoje é sobre uma API do HTML5, Web Workers. A API traz o uso de threads para o javascript, permitindo então aos desenvolvedores o desenvolvimento de aplicações com alto processamento apenas no navegador, sem a necessidade do servidor para fazer o trabalho pesado. No post veremos uma introdução rápida aos workers e seu funcionamento e desenvolveremos um exemplo para aplicar um filtro de tons de cinza em uma imagem.

Introdução

Web workers é uma API do HTML5 que permite o uso de threads em javascript. O modelo de comunicação da API é parecido com o padrão PVM, onde utiliza-se a troca de mensagens para a comunicação entre as threads. Para a troca de mensagens na API são utilizados o método postMessage e o evento message.

Como no exemplo acima, para iniciar um worker basta apenas criar uma instância de Worker apontando um arquivo .js. Um ponto interessante é que podemos utilizar o método postMessage com objetos e não apenas strings. Também é importante comentar do método terminate (ou close no worker) que encerra um worker e libera a memória e do evento error que notifica algum erro que ocorreu no worker.

Um ponto que eu particularmente vejo como uma possível falha na API é a falta de um evento terminate ou complete que indique que o worker terminou o seu trabalho.

Casos de uso

Antes de entrarmos no exemplo, vamos ver alguns possíveis usos para a API.

  • Gerar muito conteúdo HTML
  • Vamos supor que exista um relatório em HTML que possua uma tabela 10.000 linhas e 20 colunas. É uma tarefa ótima para o servidor, no entanto nos dias de hoje se vê menos o servidor gerando HTML. Desta forma, é possível criar um worker que faça requisições ajax buscando os dados e monte o HTML sem travar a página.
  • Cálculos matemáticos
  • Atualmente é possível ver exemplos de aplicações para tratar imagens ou outras tipos de mídia dentro do navegador. Uma forma de fazer este processamento sem travar a página é utilizando workers.

Exemplo

No exemplo do post vamos fazer um worker que aplica o efeito grayscale (tons de cinza) em uma imagem. Para isso, além da API Worker estaremos utilizando a API canvas também.

HTML + CSS

Nada de muito novo no HTML ou no CSS. Temos um elemento canvas que irá receber a imagem que o usuário selecionar pelo campo do tipo file. E um link que iniciará o processamento.

No arquivo main.js temos dois objetos (ou classes estáticas) para tratar de eventos e da lógica do exemplo. O arquivo poderia ter sido incluído no fim da página evitando o uso do evento DOMContentLoaded.

O objeto Canvas possui alguns métodos para ajudar a trabalhar com o canvas e separar a lógica. O método init apenas busca o elemento e pega o contexto. O método drawImage reinicia o canvas (atribuir os valores de width e height faz o canvas reiniciar) e desenha a imagem no elemento canvas da página. Veremos o método applyGrayscale adiante 🙂

O objeto Document também possui métodos para ajudar na manipulação do DOM. Inicialmente buscamos o link para aplicar o efeito e também o campo para selecionar o arquivo. Um código que pode parecer diferente é o uso do método bind no listener onImageChange, não falarei deste método no post, no entanto já escrevi sobre ele neste post. Neste contexto estamos utilizando o método bind apenas para manter o escopo em Document quando o listener onFileChange for executado.

Definimos três listeners um para aplicar o efeito onGrayscaleLinkClick, outro para desenhar a imagem no canvas onImageLoad e o que cria a imagem através do arquivo selecionado onFileChange. O listener onFileChange cria uma nova imagem new Image(), busca o arquivo e cria uma url local para o arquivo window.URL.createObjectURL(file). Depois disso apenas atribuímos o evento load para imagem para que ela seja desenhada no canvas quando for carregada.

Agora vamos ao método applyGrayscale que é onde acontece a magia dos workers.

Inicialmente buscamos os dados da imagem (basicamente um array com as informações de cor dos pixels) e iniciamos um worker chamado ImageProcessor.js. Adicionamos um listener para o evento message (que irá colocar os pixels em grayscale no canvas) e enviamos uma mensagem para o worker com os dados da imagem.

No worker inciamos um listener para o evento message e criamos um objeto para separar o código. Os dados que são enviados através do método postMessage(data) podem ser recuperados através da propriedade data no evento message. Quando o worker recebe uma mensagem, ele busca os dados (evt.data) e inicia o processamento (ImageProcessor.applyGrayscale(data.data)). O array com as informações está contido na propriedade data do objeto retornado por context.getImageData().

Informações dos pixels e grayscale

Antes de vermos o método applyGrayscale do worker, vamos ver brevemente como funcionam as informações de cor da imagem e o efeito grayscale.

O método getImageData() retorna um objeto que contém um array de bytes na propriedade data. Este array contém as informações de cada pixel da imagem, ou seja, se uma imagem tem 10×10 o array tem que ter 100 posições. No entanto não é bem assim que funciona, no exemplo o array terá 400 posições. Visto que um pixel contém 4 informações (red, green, blue, alpha), o array precisa de 4 posições para o valor de um pixel.

Desculpe se a explicação ficou breve e não muito legal, mas, segue um link com mais informações.

Para o filtro grayscale iremos utilizar a fórumla Y’ = 0,2126R + 0,7152G + 0,0722B. Para mais informações sobre o filtro, veja este artigo no wikipedia.

Por fim o nosso método applyGrayscale apenas percorre o array de dados da imagem de 4 em 4 posições, mas nunca alteramos a quarta posição visto que esta é a posição do canal alpha (tranparência) da imagem.

Após processar os dados o worker envia uma mensagem para a thread principal com os bytes da imagem em tons de cinza. Neste momento é disparado o evento message no worker na thread principal que então coloca os pixels em tons de cinza no canvas.

Para mais informações sobre web workers segue o post de Eric Bidelman no HTML5 Rocks.

Para este post era isso pessoal. Espero que tenha curtido. Os fontes estão no github.

Até a próxima.

Anúncios

2 pensamentos sobre “Colocando workers para trabalhar com HTML5

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s