JavaScript Web Workers: a Beginners Guide
em 2019, o ecossistema da web evoluiu até o ponto em que o navegador é um ambiente de execução para aplicações construídas em JavaScript. Isso se reflete na velocidade com que a indústria vem com novos frameworks, paradigmas, Carregadores de módulos e bundlers, gerentes de dependência, ferramentas de construção e gerentes de pacotes ano após ano.quando JavaScript foi concebido nos primeiros dias da internet, a direção do desenvolvimento da internet não era clara. Devido à constante e rápida mudança na indústria e ecossistema, a necessidade de compatibilidade de navegadores e da web, padrões, a evolução do JavaScript tornou-se um fluxo constante de patches, hacks e reflexões posteriores.
us Today’s mobile devices normally come with 8+ CPU cores, or 12+ GPU cores. CPUs Desktop e servidor têm até 16 núcleos, 32 threads, ou mais.
neste ambiente, ter um ambiente de programação dominante ou de scripting que é único-threaded é um gargalo.
JavaScript é um rosca simples
isto significa que, por design, os motores JavaScript — originalmente navegadores — têm um fio principal de execução, e, para colocá-lo simplesmente, o processo ou função b não pode ser executado até que o processo ou função a esteja terminado. A UI de uma página web não responde a qualquer outro processamento JavaScript enquanto está ocupada com a execução de algo — isto é conhecido como bloqueio DOM.isto é terrivelmente ineficiente, especialmente em comparação com outras línguas. se formos ao js Bin e executarmos este código na consola de JavaScript do navegador:
//noprotecti = 0;while (i < 60000) { console.log("The number is " + i); i++;}
… o todo jsbin.com o site ficará sem resposta até que o navegador Conte — e logs — para 60.000.
não seremos capazes de interagir com nada na página, porque o navegador está ocupado.
Agora, este é um processo de computação relativamente independente, e os aplicativos web de hoje muitas vezes envolvem tarefas muito mais exigentes.
precisamos ser capazes de computar as coisas em segundo plano, enquanto o usuário interage perfeitamente com a página.
Web Workers
the W3C published a first draft of the web workers standard in 2009. A especificação completa pode ser encontrada no Web Hypertext Application Technology Working Group website — ou WHATWG — um web standards body alternativa ao W3C.
web workers é um sistema assíncrono, ou Protocolo, para páginas web para executar tarefas em segundo plano, independentemente do thread principal e UI site. É um ambiente isolado que está isolado do objeto window
, odocument
objeto, acesso direto à internet e é mais adequado para tarefas computacionais de longa duração ou exigentes.
para além dos trabalhadores da web — um sistema dedicado à multithreading — existem outras formas de conseguir o processamento asnicrono em JavaScript, tais como chamadas Ajax assíncronas, e loop de eventos.
para demonstrar isso, vamos voltar para JS Bin e tentar este trecho:
console.log("A");setTimeout(function(){console.log("B");},2000);console.log("C");setTimeout(function(){console.log("D");},0);console.log("E");setTimeout(function(){console.log("F");},1000);
quando executarmos isto, a nossa sequência de log é A, C, E, D, F, B
. O navegador primeiro escalonar as operações sem o tempo-limite, como eles vêm, e então ele executa o setTimeout()
funções na ordem de seus respectivos atrasos especificados. No entanto, esta assíncronicidade não deve ser automaticamente confundida com multithreading. Dependendo da máquina hospedeira, esta pode ser muitas vezes apenas uma pilha de linhas simples das chamadas na ordem que explicamos.
Web Workers & Multithreading
As Mozilla’s JavaScript reference website explains, web workers are a ” means for web content to run scripts in background threads.”
Nós os usamos da seguinte forma: Nós verificamos para a disponibilidade do Worker()
construtor no navegador, e se ele está disponível, nós instanciamos um objeto trabalhador, com o URL do script como o argumento. Este programa será executado num tópico separado.
o script deve ser servido do mesmo host ou domínio por razões de segurança, e essa é também a razão pela qual os trabalhadores da web não vão trabalhar se abrirmos o arquivo localmente com umfile://
esquema.
if (typeof(Worker) !== "undefined") { worker = new Worker("worker.js");}
agora definimos este código no worker.js
ficheiro:
i = 0;while (i < 200000) { postMessage("Web Worker Counter: " + i); i++;}
If you want to write high-quality JavaScript web worker files, check out our book, JavaScript: Best Practice.
A Separação de linhas
Uma coisa importante a notar aqui é a separação de window
e document
escopo de execução na janela principal do browser segmento e o worker
escopo.
A fim de fazer uso do fioworker
, estes dois âmbitos precisam ser capazes de se comunicar. Para conseguir isso, utilizamos a tag postMessage()
função dentro de worker.js
arquivo — enviar mensagens para o navegador principal segmento e o worker.onmessage
ouvinte no thread principal para ouvir worker
mensagens.
também podemos enviar mensagens do fio principal do navegador para o worker
thread ou função. A única diferença é que invertemos as coisas, e chamamos worker.postMessage()
na linha principal, e onmessage
na linha de trabalho. Para citar a referência de desenvolvimento do Mozilla:
Observe que
onmessage
epostMessage()
precisa ser penduradaWorker
objeto, quando usada no script principal segmento, mas não quando usado no trabalho. Isto porque, dentro do trabalhador, o trabalhador é efetivamente o escopo global.
podemos usar o métodoterminate()
da mesma forma, para acabar com a execução do nosso trabalhador.
com tudo isso em mente, chegamos a este exemplo:
índice.html
<!DOCTYPE html><html><head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>Web Workers Example</title> <style type="text/css"> body {padding-top:28px;} .output-cont {margin-left:12%; margin-top:28px;} .output-cont h3 {width:200px; height:100%;} .output-cont button {padding:4px 8px; font-size:1.1rem; font-family:sans-serif; } </style></head><body><div class="output-cont"><button onclick="testWorker()">start worker</button><h3></h3><button onclick="terminateWorker()">terminate worker</button></div><br/><div class="output-cont"><button onclick="testMainThread()">start blocking thread</button><h3></h3></div><br/><div class="output-cont"><button onclick="alert('browser responsive!')">test browser responsiveness</button></div> <script> var worker; function testWorker() { if (typeof(Worker) !== "undefined") { if (typeof(worker) == "undefined") { worker = new Worker("worker.js"); } worker.onmessage = function(event) { document.getElementById("workerOutput").innerHTML = event.data; }; } else { document.getElementById("workerOutput").innerHTML = "Web Workers are not supported in your browser"; } } function terminateWorker() { worker.terminate(); worker = undefined; } function testMainThread() { for (var i = 0; i < 200000; i++) { document.getElementById("mainThreadOutput").innerHTML = "Main Thread Counter: " + i; } } </script></body></html>
e trabalhador.js:
i = 0;while (i < 200000) { postMessage("Web Worker Counter: " + i); i++;}
isto nos dá a oportunidade de testar os efeitos da execução de linha principal no comportamento da página e desempenho versus os efeitos do trabalhador da web.
neste tutorial, nós usamos http-server
para servir os arquivos localmente.
Agora podemos ver que o thread de trabalho não bloquear a interatividade do principal processo de navegador, e um loop através de 200.000 números não afeta o thread principal. Os números no elemento #workerOutput
são atualizados em cada iteração.
O fio de bloqueio, ou fio principal, quando envolvido em um laço, bloqueia toda interatividade (nós definimos o número de iterações para 200.000 aqui, mas será ainda mais óbvio se aumentarmos para 2.000.000).
mais Uma coisa que nos aponta para uma nova thread principal é que o processo de trabalho atualiza a página em cada iteração, e o loop na linha principal (definido no index.html
) atualiza apenas o #mainThreadOutput
elemento na última iteração.
Isto é porque o navegador é muito consumida com a contagem (for
loop) para ser capaz de redesenhar o DOM, então ele faz isso apenas uma vez seus negócios com o for
loop é totalmente feito (no fim do ciclo).
conclusão
neste artigo, introduzimos web workers, uma tecnologia que ajuda a indústria da web a acompanhar cada vez mais aplicações web exigentes. Isto é feito fornecendo uma maneira para os aplicativos web para alavancar dispositivos multi-processadores e multi-threaded, concedendo alguns super-threaded super-poderes para JavaScript.
Web workers turn the mobile and desktop browser environments into application platforms, providing them with a strict execution environment. Este Rigor pode nos forçar a fornecer a cópia de objetos entre vários threads, e planejar nossas aplicações com essas restrições em mente.