Web Workers em JavaScript

Web Workers em JavaScript

Este artigo explica os Web Workers em JavaScript.

YouTube Video

javascript-web-worker.html
  1<!DOCTYPE html>
  2<html lang="en">
  3<head>
  4  <meta charset="UTF-8">
  5  <title>JavaScript &amp; HTML</title>
  6  <style>
  7    * {
  8        box-sizing: border-box;
  9    }
 10
 11    body {
 12        margin: 0;
 13        padding: 1em;
 14        padding-bottom: 10em;
 15        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
 16        background-color: #f7f9fc;
 17        color: #333;
 18        line-height: 1.6;
 19    }
 20
 21    .container {
 22        max-width: 800px;
 23        margin: 0 auto;
 24        padding: 1em;
 25        background-color: #ffffff;
 26        border: 1px solid #ccc;
 27        border-radius: 10px;
 28        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
 29    }
 30
 31    .container-flex {
 32        display: flex;
 33        flex-wrap: wrap;
 34        gap: 2em;
 35        max-width: 1000px;
 36        margin: 0 auto;
 37        padding: 1em;
 38        background-color: #ffffff;
 39        border: 1px solid #ccc;
 40        border-radius: 10px;
 41        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
 42    }
 43
 44    .left-column, .right-column {
 45        flex: 1 1 200px;
 46        min-width: 200px;
 47    }
 48
 49    h1, h2 {
 50        font-size: 1.2rem;
 51        color: #007bff;
 52        margin-top: 0.5em;
 53        margin-bottom: 0.5em;
 54        border-left: 5px solid #007bff;
 55        padding-left: 0.6em;
 56        background-color: #e9f2ff;
 57    }
 58
 59    button {
 60        display: block;
 61        margin: 1em auto;
 62        padding: 0.75em 1.5em;
 63        font-size: 1rem;
 64        background-color: #007bff;
 65        color: white;
 66        border: none;
 67        border-radius: 6px;
 68        cursor: pointer;
 69        transition: background-color 0.3s ease;
 70    }
 71
 72    button:hover {
 73        background-color: #0056b3;
 74    }
 75
 76    #output {
 77        margin-top: 1em;
 78        background-color: #1e1e1e;
 79        color: #0f0;
 80        padding: 1em;
 81        border-radius: 8px;
 82        min-height: 200px;
 83        font-family: Consolas, monospace;
 84        font-size: 0.95rem;
 85        overflow-y: auto;
 86        white-space: pre-wrap;
 87    }
 88
 89    .highlight {
 90        outline: 3px solid #ffc107; /* yellow border */
 91        background-color: #fff8e1;  /* soft yellow background */
 92        transition: background-color 0.3s ease, outline 0.3s ease;
 93    }
 94
 95    .active {
 96        background-color: #28a745; /* green background */
 97        color: #fff;
 98        box-shadow: 0 0 10px rgba(40, 167, 69, 0.5);
 99        transition: background-color 0.3s ease, box-shadow 0.3s ease;
100    }
101  </style>
102</head>
103<body>
104    <div class="container">
105        <h1>JavaScript Console</h1>
106        <button id="executeBtn">Execute</button>
107        <div id="output"></div>
108    </div>
109
110    <script>
111        // Override console.log to display messages in the #output element
112        (function () {
113            // Override console.log
114            const originalLog = console.log;
115            console.log = function (...args) {
116                originalLog.apply(console, args);
117                const message = document.createElement('div');
118                message.textContent = args.map(String).join(' ');
119                output.appendChild(message);
120            };
121
122            // Override console.error
123            const originalError = console.error;
124            console.error = function (...args) {
125                originalError.apply(console, args);
126                const message = document.createElement('div');
127                message.textContent = args.map(String).join(' ');
128                message.style.color = 'red'; // Color error messages red
129                output.appendChild(message);
130            };
131        })();
132
133        document.getElementById('executeBtn').addEventListener('click', () => {
134            // Prevent multiple loads
135            if (document.getElementById('externalScript')) return;
136
137            const script = document.createElement('script');
138            script.src = 'javascript-web-worker.js';
139            script.id = 'externalScript';
140            //script.onload = () => console.log('javascript-web-worker.js loaded and executed.');
141            //script.onerror = () => console.log('Failed to load javascript-web-worker.js.');
142            document.body.appendChild(script);
143        });
144    </script>
145</body>
146</html>

Web Worker no JavaScript

Web Worker em JavaScript é um mecanismo que permite que o código seja executado em uma thread separada da thread principal. Isso permite que cálculos pesados e operações de longa duração sejam executados de forma assíncrona, evitando o bloqueio do thread principal. Ao usar Web Worker, a responsividade da interface do usuário melhora e o desempenho do aplicativo é aprimorado.

O uso básico de Web Worker

Vamos dar uma olhada no uso básico de Web Worker.

Um novo Web Worker é criado especificando um arquivo JavaScript.

1// worker.js (created as a separate file)
2onmessage = function(event) {
3    // Receive a message
4    const data = event.data;
5    // Perform heavy computation or processing
6    const result = data * 2;
7    // Return the result to the main thread
8    postMessage(result);
9};
 1// Main thread (main.js)
 2const worker = new Worker('worker.js');
 3
 4// Send a message to the worker
 5worker.postMessage(10);
 6
 7// Receive a message from the worker
 8worker.onmessage = function(event) {
 9    console.log('Result from Worker: ', event.data); // Result: 20
10};
11
12// Error handling
13worker.onerror = function(error) {
14    console.error('Worker error: ', error);
15};
  • Este código demonstra o mecanismo básico de usar um Web Worker para solicitar uma computação a partir da thread principal e receber o resultado de forma assíncrona. Envia 10 como uma mensagem para o Web Worker e recebe 20 como mensagem de resultado. A thread principal e o Web Worker se comunicam enviando e recebendo mensagens para solicitar e receber resultados de processamento.

Funções básicas

Web Worker oferece as seguintes funcionalidades básicas.

  • postMessage e onmessage Usado para enviar e receber mensagens entre a thread principal e o Web Worker. Envie dados com postMessage e os receba com onmessage.
  • Independência de Thread O Web Worker opera completamente independente da thread principal. Portanto, variáveis e funções definidas no thread principal não podem ser acessadas. Os dados necessários precisam ser passados por postMessage.
  • Importação de Script Para carregar scripts externos dentro de um Web Worker, use importScripts().
1// mathUtils.js
2function double(n) {
3    return n * 2;
4}
1// worker.js
2importScripts('mathUtils.js');
3
4onmessage = function(event) {
5    const input = event.data;
6    const result = double(input); // mathUtils.jsの関数を使用
7    postMessage(result);
8};
 1// Main thread (main.js)
 2const worker = new Worker('worker.js');
 3
 4// Send a message to the worker
 5worker.postMessage(10);
 6
 7// Receive a message from the worker
 8worker.onmessage = function(event) {
 9    console.log('Result from Worker: ', event.data); // Result: 20
10};
11
12// Error handling
13worker.onerror = function(error) {
14    console.error('Worker error: ', error);
15};

Alternativamente, você também pode usar import conforme mostrado abaixo.

1// lib.js
2
3// Simulated CPU-intensive task
4export function doHeavyWork(n) {
5    return n * 2;
6}
1// worker.js
2import { doHeavyWork } from './lib.js';
3
4self.onmessage = (event) => {
5  const data = event.data;
6  const result = doHeavyWork(data);
7  self.postMessage(result);
8};
 1// Main thread (main.js)
 2const worker = new Worker('worker.js', { type: 'module' });
 3
 4// Send a message to the worker
 5worker.postMessage(10);
 6
 7// Receive a message from the worker
 8worker.onmessage = function(event) {
 9    console.log('Result from Worker: ', event.data); // Result: 20
10};
11
12// Error handling
13worker.onerror = function(error) {
14    console.error('Worker error: ', error);
15};
  • Ao especificar type: 'module' no argumento do new Worker, você pode tratar o worker como um módulo ES e usar a sintaxe de import.

Diferenças entre Web Worker e funções async

Web Worker

Características
  • Isolamento de Thread O Web Worker executa o código JavaScript em uma thread separada. Isso permite que processamentos pesados sejam realizados sem bloquear a thread principal (thread de UI).
  • Processamento Concorrente Usar Web Worker permite que programas JavaScript realizem processamento concorrente em múltiplas threads.
  • Comunicação via Mensagens O Web Worker e a thread principal não compartilham dados diretamente, e trocam mensagens usando postMessage e onmessage.
  • Não Pode Acessar a UI Web Worker não pode acessar o DOM, então não pode manipular a interface de usuário diretamente.
Casos de uso
  • É adequado para processos de computação pesada, como processamento de imagens, análise de dados e criptografia.
  • Pode ser usado quando você não deseja bloquear a thread principal.

async

Características
  • Simplificando o Processamento Assíncrono A função async é uma sintaxe para tornar o processamento assíncrono mais legível, utilizando Promise internamente.
  • Thread Única Todas as funções async são executadas na thread principal. Portanto, é necessário elaborar formas de evitar o bloqueio da thread de UI.
  • Ideal para Operações de I/O É adequado para tarefas assíncronas como comunicação de rede e leitura de arquivos, mas não para cálculos pesados.
Casos de uso
  • É adequado para comunicação de rede, como chamadas de API.
  • É adequado para leitura e escrita de arquivos usando APIs do navegador ou Node.js.

Diferenças Principais

Características Web Worker async
Ambiente de Execução Thread separada Thread principal
Propósito Processamento paralelo, aliviar cálculos pesados Descrição concisa de operações assíncronas
Acesso ao DOM Não é possível Possível
Método de Comunicação Troca de mensagens (ex.: postMessage) Não é necessário (tratado via chamadas de função direta ou await)
Casos de Uso Cálculos demorados, análise de dados Operações de I/O, chamadas de API

Quando Usar Cada Um

Para tarefas que exigem uso intensivo de CPU, você pode usar Web Worker para reduzir a carga na thread principal. Por outro lado, para comunicação de rede ou operações de I/O, você pode simplificar seu código usando async/await.

Ao combinar ambos adequadamente, você pode alcançar um processamento assíncrono eficiente.

Exemplos de Uso de Web Worker

Exemplo de delegação de cálculos pesados

A seguir está um exemplo de delegação de cálculos pesados.

 1// worker.js
 2onmessage = function(event) {
 3    const num = event.data;
 4    const result = fibonacci(num);
 5    postMessage(result);
 6};
 7
 8function fibonacci(n) {
 9    if (n <= 1) return n;
10    return fibonacci(n - 1) + fibonacci(n - 2);
11}
1// Main thread
2const worker = new Worker('worker.js');
3
4worker.onmessage = function(event) {
5    console.log('Fibonacci result: ', event.data);
6};
7
8worker.postMessage(40); // Delegate heavy computation to the worker
  • Este código é um exemplo de como usar um Web Worker para separar e executar tarefas pesadas, como o cálculo da sequência de Fibonacci, fora da thread principal.

Um exemplo de especificação de um nome de tarefa

A seguir está um exemplo de envio e recebimento de mensagens especificando um nome de tarefa.

 1// worker.js
 2self.onmessage = function(event) {
 3    switch (event.data.task) {
 4        case 'add':
 5            const result = event.data.a + event.data.b;
 6            self.postMessage({ task: 'result', value: result });
 7            break;
 8        default:
 9            self.postMessage({ task: 'error', message: 'Invalid Task' });
10    }
11};
 1// Main thread
 2const worker = new Worker('worker.js');
 3
 4worker.onmessage = function(event) {
 5    switch (event.data.task) {
 6        case 'result':
 7            console.log('Task result: ', event.data.value);
 8            break;
 9        case 'error':
10            console.error('Error: ', event.data.message);
11            break;
12    }
13};
14
15worker.postMessage({ task: 'add', a: 10, b: 20 });
  • Este código é um exemplo de como despachar o processamento com base no nome da tarefa na mensagem, fazendo com que o Web Worker retorne os resultados dos cálculos ou erros para a thread principal junto com o nome da tarefa.

Notas

Ao usar Web Worker, tenha em mente os seguintes pontos.

  • Não Pode Acessar o DOM Web Worker não pode manipular a interface de usuário nem acessar o DOM. A manipulação do DOM precisa ser feita no thread principal.
  • Sobrecarga na Comunicação Há uma certa sobrecarga na troca de dados entre a thread principal e o Web Worker. Isso pode afetar o desempenho, especialmente ao trocar grandes volumes de dados com frequência.
  • Política de Mesma Origem (Same-Origin Policy) Os scripts de Web Worker estão sujeitos à política de mesma origem. Os scripts não podem ser carregados de domínios diferentes.

O uso de Web Worker pode melhorar o desempenho e a responsividade da sua aplicação, mas é importante utilizá-lo adequadamente, considerando limitações como a incapacidade de manipular o DOM.

Você pode acompanhar o artigo acima usando o Visual Studio Code em nosso canal do YouTube. Por favor, confira também o canal do YouTube.

YouTube Video