Com o HTML5, é possível criar experiências maravilhosas com a conveniência de recursos que antes eram encontrados apenas em plataformas ricas para Desktop ou plug-ins como Flash e Silverlight.
A quantidade de novos recursos disponíveis é muito grande, e a necessidade de utilizar muitos desses recursos simultaneamente também é crescente.
E, como todos sabemos, quanto mais scripts sendo executados “ao mesmo tempo”, maior é a carga de processamento para a Thread de UI, na qual acontecem as atualizações da interface com o usuário. Mesmo com os esforços para a melhoria no modelo de execução de scripts nos navegadores mais modernos, em algum momento, fatalmente esbarraremos nos limites de processamento físicos da Thread principal, seja em falta de resposta ou na interrupção de scripts de longa duração por interações do usuário.
Para evitar esse tipo de situação, existe uma especificação nova que acrescenta bastante poder ao HTML5: Web Workers.
Com Web Workers, é possível executar scripts em threads distintas da thread de UI, o que permite muito mais eficiência na execução e fluidez na interface, principalmente por se tratar de um modelo que utiliza os núcleos (cores) do processador disponível.
Até então, esse tipo de execução só era acessível para plataformas não HTML através de APIs não tão amigáveis para o desenvolvedor.
Uma das características mais interessantes das especificações do W3C é a simplicidade de utilização dos recursos, e isso se aplica a Web Workers, o que torna o trabalho muito simples para o desenvolvedor.
A maneira mais simples para se utilizar um WebWorker é utilizar um arquivo de script separado. Poderia também ser utilizado um script inline e outras modalidades como DedicatedWorkers e SharedWorkers, porém, para este artigo de introdução, vamos focar na maneira mais prática.
Declarando o Worker na thread da UI:
Default.htm
var worker = new Worker("myscript.js");Isso faz com que o Worker instancie o script para atuar como o Worker em background.
É importante adicionar eventhandlers aos eventos do Workerna thread de UI, onmessage e onerror
worker.onmessage = onWorkerMessage; worker.onerror = onWorkerError;Abaixo, a implementação das duas funções que vão ser executadas quando os eventos forem disparados:
functiononWorkerMessage(e) { label.innerHTML = e.data; } functiononWorkerError(e) { // Faça algo quando ocorrer um erro }Agora que o Worker já está pronto, é necessário utilizar o método postMessage() para que ele comece a ser executado:
worker.postMessage("start");É possível enviar objetos mais complexos via postMessage e utilizar esses objetos para uma comunicação mais precisa entre as Threads UI e o Background.
Também é importante adicionar o eventhandler de mensagens ao script que será executado como o Worker para efetuar a troca de mensagens/comandos.
myscript.js
self.onmessage = onWorkerMessage; functiononWorkerMessage(e) { switch(e.data) { case "start": self.postMessage("Iniciando..."); break; case "stop": self.postMessage("Parando..."); self.close(); break; } }Assim que o Worker receber a primeira mensagem “start”, ele retornará uma mensagem para a thread UI que exibirá essa mensagem para o usuário.
Mas, além de tratarmos as mensagens recebidas pelo Worker, também devemos implementar a lógica que será executada em background.
Neste caso, eu escolhi utilizar um loop infinito que incrementa uma variável para que a visualização seja clara do exemplo funcionando.
var value = 0; while (true) { self.postMessage("Valor atual: " + value++); }Basicamente, esse loop avisa à thread de UI o valor atual à cada atualização e que, por sua vez, exibe o valor para o usuário.
Existem duas formas de parar a execução de um Workers. Podemos utilizar o método terminate() na thread da UI ou o método close() na thread em background.
Neste caso, podemos utilizar a interface para enviar mensagens para parar o processamento do worker e então terminá-lo:
<buttononclick="stop();">Parar Worker</button> function stop() { worker.postMessage("stop"); }A mensagem “stop” já foi tratada pelo script do nosso Worker customizado, porém como tudo acontece muito rápido, as mensagens não chegam a ser exibidas devido ao fato de o Worker já ter sido fechado. A dica aqui é utilizar mais mensagens e só terminar o Worker ao final de todo o processamento necessário.
Abaixo o código completo da página HTML e do Script:
Default.htm
<!doctypehtml> <html> <head> <title>Web Worker</title> <script> var worker; var label; functioninit() { label = document.getElementById("label"); worker = new Worker("myscript.js"); worker.onmessage = onWorkerMessage; worker.onerror = onWorkerError; worker.postMessage("start"); } functiononWorkerMessage(e) { label.innerHTML = e.data; } functiononWorkerError(e) { // Faça algo quando ocorrer um erro } function stop() { worker.postMessage("stop"); } </script> </head> <bodyonload="init();"> <divid="label"></div> <buttononclick="stop();">Parar Worker</button> </body> </html>myscript.js
self.onmessage = onWorkerMessage; functiononWorkerMessage(e) { switch(e.data) { case "start": self.postMessage("Iniciando..."); break; case "stop": self.postMessage("Parando..."); self.close(); break; } } var value = 0; while(true) { self.postMessage("Valoratual: " + value++); }
Vejam abaixo a variação de utilização do processamento da minha máquina (que possui quatro núcleos) ao utilizar o Web Worker.
Antes de acionar a página do Worker:
Durante o processamento do Woker:
Como vocês puderam notar, a API de Workers define automaticamente a afinidade entre threads e núcleos do meu processador e garante um processamento muito rápido sem interferir na thread de UI.
Vale a pena conferir este comparativo entre o processamento de um script no modelo baseado na thread de UI e utilizando o Workers que é baseado no test262 do Ecmascript.
Essas implementações funcionam nas versões mais atuais dos navegadores. Por se tratar de um Draft de especificação e implementação por parte dos navegadores, você encontrará diferença na performance e falhas na execução dos testes, mas é perfeitamente viável para iniciar o desenvolvimento.
O código deste artigo é baseado na especificação do W3C e foi testado com o Internet Explorer 10 Platform Preview, que pode ser instalado a partir deste link
***
Veja mais detalhes no HTML5 & JavaScript Center
Nenhum comentário:
Postar um comentário