Pracownicy sieciowi w JavaScript

Pracownicy sieciowi w JavaScript

Ten artykuł wyjaśnia temat pracowników sieciowych w 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 w JavaScript

Web Worker w JavaScript to mechanizm, który pozwala na uruchamianie kodu w oddzielnym wątku od głównego wątku. Pozwala to na asynchroniczne wykonywanie ciężkich obliczeń i operacji długotrwałych, zapobiegając blokowaniu głównego wątku. Korzystając z Web Worker, poprawia się responsywność interfejsu użytkownika, a wydajność aplikacji wzrasta.

Podstawowe zastosowanie Web Worker

Przyjrzyjmy się podstawowemu użyciu Web Workera.

Nowy Web Worker jest tworzony poprzez wskazanie pliku 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};
  • Ten kod demonstruje podstawowy mechanizm wykorzystania Web Workera do żądania obliczeń z głównego wątku i odbierania wyników asynchronicznie. Wysyła 10 jako wiadomość do Web Workera i otrzymuje 20 jako wiadomość z wynikiem. Wątek główny i Web Worker komunikują się poprzez wysyłanie i odbieranie wiadomości, aby żądać i odbierać wyniki przetwarzania.

Podstawowe funkcje

Web Worker oferuje następujące podstawowe funkcje.

  • postMessage i onmessage Używane do wysyłania i odbierania wiadomości między głównym wątkiem a Web Workerem. Dane wysyłane za pomocą postMessage i odbierane za pomocą onmessage.
  • Niezależność wątków Web Worker działa całkowicie niezależnie od głównego wątku. Dlatego nie można uzyskać dostępu do zmiennych i funkcji zdefiniowanych w głównym wątku. Wymagane dane muszą być przekazywane za pomocą postMessage.
  • Import skryptów Aby załadować zewnętrzne skrypty w Web Workerze, użyj 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};

Alternatywnie możesz także użyć import, jak pokazano poniżej.

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};
  • Podając type: 'module' w argumencie new Worker, możesz traktować workera jako moduł ES i używać składni import.

Różnice pomiędzy Web Worker a funkcjami async

Web Worker

Funkcje
  • Izolacja wątków Web Worker wykonuje kod JavaScript w oddzielnym wątku. Pozwala to na wykonywanie ciężkich obliczeń bez blokowania głównego wątku (wątku UI).
  • Przetwarzanie współbieżne Używanie Web Workera pozwala programom JavaScript na wykonywanie współbieżnego przetwarzania w wielu wątkach.
  • Komunikacja wiadomościami Web Worker i główny wątek nie współdzielą danych bezpośrednio i wymieniają wiadomości za pomocą postMessage i onmessage.
  • Brak dostępu do interfejsu użytkownika (UI) Web Worker nie ma dostępu do DOM, więc nie może bezpośrednio manipulować interfejsem użytkownika (UI).
Przypadki użycia
  • Jest odpowiedni dla procesów wymagających dużej mocy obliczeniowej, takich jak przetwarzanie obrazów, analiza danych i szyfrowanie.
  • Można go użyć, gdy nie chcesz blokować głównego wątku.

async

Funkcje
  • Uproszczenie przetwarzania asynchronicznego Funkcja async to składnia ułatwiająca czytelność przetwarzania asynchronicznego, wewnętrznie wykorzystuje Promise.
  • Pojedynczy wątek Wszystkie funkcje async są wykonywane w głównym wątku. Dlatego trzeba opracować sposoby uniknięcia blokowania wątku UI.
  • Optymalne dla operacji wejścia/wyjścia (I/O) Nadaje się do zadań asynchronicznych, takich jak komunikacja sieciowa i czytanie plików, ale nie do ciężkich obliczeń.
Przypadki użycia
  • Nadaje się do komunikacji sieciowej, np. wywołań do API.
  • Jest odpowiednie do odczytu i zapisu plików za pomocą API przeglądarki lub Node.js.

Kluczowe różnice

Funkcje Web Worker async
Środowisko wykonawcze Oddzielny wątek Główny wątek
Cel Przetwarzanie równoległe, odciążenie ciężkich obliczeń Zwięzły opis operacji asynchronicznych
Dostęp do DOM Niemożliwy Możliwy
Metoda komunikacji Przekazywanie wiadomości (np. postMessage) Nie wymagane (zarządzane przez bezpośrednie wywołania funkcji lub await)
Przypadki użycia Czasochłonne obliczenia, analiza danych Operacje I/O, wywołania API

Kiedy używać każdego z nich

W przypadku zadań wymagających intensywnego wykorzystania procesora można użyć Web Worker, aby zmniejszyć obciążenie głównego wątku. Natomiast w przypadku komunikacji sieciowej lub operacji I/O można uprościć kod, używając async/await.

Poprzez odpowiednie połączenie obu można osiągnąć wydajne przetwarzanie asynchroniczne.

Przykłady użycia Web Worker

Przykład przenoszenia ciężkich obliczeń

Następnie przykład przenoszenia ciężkich obliczeń poza główny wątek.

 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
  • Ten kod jest przykładem użycia Web Workera do oddzielenia i wykonania ciężkich zadań, takich jak obliczanie ciągu Fibonacciego, od głównego wątku.

Przykład określania nazwy zadania

Następnie przykład wysyłania i odbierania wiadomości przez określenie nazwy zadania.

 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 });
  • Ten kod jest przykładem przekierowywania przetwarzania na podstawie nazwy task w wiadomości, gdzie Web Worker zwraca wyniki obliczeń lub błędy do głównego wątku razem z nazwą zadania.

Notatki

Podczas używania Web Workera, pamiętaj o poniższych kwestiach.

  • Brak dostępu do DOM Web Worker nie może manipulować interfejsem użytkownika ani uzyskać dostępu do DOM. Manipulacje w DOM muszą być wykonywane w głównym wątku.
  • Koszt komunikacji Wymiana danych między głównym wątkiem a Web Workerem wiąże się z pewnymi narzutami. Może to wpłynąć na wydajność, zwłaszcza przy częstej wymianie dużych ilości danych.
  • Polityka tego samego pochodzenia (same-origin) Skrypty Web Workerów podlegają polityce tego samego pochodzenia. Skrypty nie mogą być ładowane z różnych domen.

Korzystanie z Web Worker może poprawić wydajność i responsywność aplikacji, ale ważne jest odpowiednie użycie, biorąc pod uwagę takie ograniczenia, jak brak możliwości manipulacji DOM.

Możesz śledzić ten artykuł, korzystając z Visual Studio Code na naszym kanale YouTube. Proszę również sprawdzić nasz kanał YouTube.

YouTube Video