Web Workers trong JavaScript
Bài viết này giải thích về Web Workers trong JavaScript.
YouTube Video
javascript-web-worker.html
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <title>JavaScript & 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
trong JavaScript
Web Worker
trong JavaScript là một cơ chế cho phép mã chạy trên một luồng riêng biệt với luồng chính. Điều này cho phép thực hiện tính toán nặng và các tác vụ chạy lâu theo cách không đồng bộ, ngăn chặn luồng chính bị chặn. Bằng cách sử dụng Web Worker
, khả năng phản hồi của giao diện người dùng được cải thiện và hiệu suất ứng dụng được nâng cao.
Cách sử dụng cơ bản của Web Worker
Hãy cùng tìm hiểu cách sử dụng cơ bản của Web Worker
.
Một Web Worker
mới được tạo ra bằng cách chỉ định một tập tin 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};
- Đoạn mã này minh họa cơ chế cơ bản của việc sử dụng
Web Worker
để yêu cầu tính toán từ luồng chính và nhận kết quả một cách bất đồng bộ. Nó gửi10
như một thông điệp đếnWeb Worker
và nhận về20
như thông điệp kết quả. Luồng chính vàWeb Worker
giao tiếp với nhau bằng cách gửi và nhận các thông điệp để yêu cầu và nhận kết quả xử lý.
Các chức năng cơ bản
Web Worker
cung cấp các chức năng cơ bản sau đây.
postMessage
vàonmessage
Được sử dụng để gửi và nhận thông điệp giữa luồng chính vàWeb Worker
. Gửi dữ liệu vớipostMessage
và nhận dữ liệu vớionmessage
.- Sự độc lập của luồng
Web Worker
hoạt động hoàn toàn độc lập với luồng chính. Do đó, không thể truy cập các biến và hàm được định nghĩa trong luồng chính. Dữ liệu cần thiết cần được truyền quapostMessage
. - Nhập khẩu tập lệnh
Để nạp các tập lệnh bên ngoài trong
Web Worker
, hãy sử dụngimportScripts()
.
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};
Ngoài ra, bạn cũng có thể sử dụng import
như được trình bày dưới đây.
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};
- Bằng cách chỉ định
type: 'module'
trong đối số củanew Worker
, bạn có thể xử lý worker như một mô-đun ES và sử dụng cú phápimport
.
Sự khác biệt giữa Web Worker
và các hàm async
Web Worker
Tính năng
- Cách ly luồng
Web Worker
thực hiện mã JavaScript trên một luồng riêng biệt. Điều này cho phép thực hiện xử lý tính toán nặng mà không làm chặn luồng chính (UI thread). - Xử lý đồng thời
Sử dụng
Web Worker
cho phép chương trình JavaScript thực hiện xử lý đồng thời trên nhiều luồng. - Giao tiếp qua thông điệp
Web Worker
và luồng chính không chia sẻ dữ liệu trực tiếp mà trao đổi thông điệp bằng cách sử dụngpostMessage
vàonmessage
. - Không thể truy cập giao diện người dùng
Web Worker
không thể truy cập vào DOM, vì vậy nó không thể thao tác trực tiếp với giao diện người dùng.
Trường hợp sử dụng
- Nó phù hợp cho các quy trình tính toán nặng như xử lý hình ảnh, phân tích dữ liệu và mã hóa.
- Nó có thể được sử dụng khi bạn không muốn chặn luồng chính.
async
Tính năng
- Đơn giản hóa xử lý bất đồng bộ
Hàm
async
là cú pháp giúp xử lý bất đồng bộ dễ đọc hơn, bên trong sử dụngPromise
. - Luồng đơn
Tất cả các hàm
async
đều chạy trên luồng chính. Do đó, bạn cần tìm cách tránh chặn luồng UI. - Tối ưu cho các thao tác I/O Nó phù hợp cho các tác vụ bất đồng bộ như giao tiếp mạng và đọc dữ liệu từ tập tin, nhưng không phù hợp cho các phép tính nặng.
Trường hợp sử dụng
- Nó phù hợp cho các tác vụ giao tiếp mạng như gọi API.
- Nó phù hợp cho việc đọc và ghi tập tin bằng API của trình duyệt hoặc Node.js.
Sự Khác Biệt Chính
Tính năng | Web Worker | async |
---|---|---|
Môi Trường Thực Thi | Luồng riêng | Luồng chính |
Mục Đích | Xử lý song song, giảm tải các phép tính nặng | Mô tả đơn giản về các hoạt động bất đồng bộ |
Truy Cập DOM | Không khả dụng | Khả dụng |
Phương Thức Giao Tiếp | Truyền thông qua tin nhắn (ví dụ, postMessage ) |
Không bắt buộc (xử lý qua các cuộc gọi hàm trực tiếp hoặc await ) |
Trường Hợp Sử Dụng | Các phép tính tiêu tốn nhiều thời gian, phân tích dữ liệu | Các thao tác I/O, cuộc gọi API |
Khi Nào Sử Dụng Mỗi Loại
Đối với các tác vụ yêu cầu CPU cao, bạn có thể sử dụng Web Worker
để giảm tải cho luồng chính. Mặt khác, đối với giao tiếp mạng hoặc các thao tác I/O, bạn có thể đơn giản hóa mã của mình bằng cách sử dụng async
/await
.
Bằng cách kết hợp cả hai một cách hợp lý, bạn có thể đạt được quá trình xử lý bất đồng bộ hiệu quả.
Ví dụ về Sử Dụng Web Worker
Ví dụ về chuyển tính toán nặng ra ngoài
Tiếp theo là một ví dụ về cách chuyển giao các phép tính nặng.
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
- Đoạn mã này là ví dụ về cách sử dụng Web Worker để tách và thực hiện các tác vụ nặng như tính dãy Fibonacci ra khỏi luồng chính.
Ví dụ về việc chỉ định tên tác vụ
Tiếp theo là ví dụ về gửi và nhận tin nhắn bằng cách chỉ định tên tác vụ.
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 });
- Đoạn mã này là ví dụ về cách xử lý theo tên
task
trong tin nhắn, vớiWeb Worker
trả về kết quả tính toán hoặc lỗi về luồng chính cùng với tên tác vụ.
Ghi chú
Khi sử dụng Web Worker
, hãy lưu ý các điểm sau.
- Không thể truy cập DOM
Web Worker
không thể thao tác với giao diện người dùng hay truy cập DOM. Thao tác DOM cần được thực hiện trong luồng chính. - Chi phí giao tiếp
Có một chút chi phí khi trao đổi dữ liệu giữa luồng chính và
Web Worker
. Điều này có thể ảnh hưởng đến hiệu suất, đặc biệt khi trao đổi lượng lớn dữ liệu thường xuyên. - Chính sách cùng nguồn gốc (Same-Origin Policy)
Các tập lệnh
Web Worker
bị ràng buộc bởi chính sách cùng nguồn gốc (same-origin policy). Các tập lệnh không thể được tải từ các miền khác nhau.
Việc sử dụng Web Worker
có thể cải thiện hiệu suất và tính phản hồi của ứng dụng của bạn, nhưng điều quan trọng là phải sử dụng nó một cách phù hợp với các giới hạn như không thể thao tác DOM.
Bạn có thể làm theo bài viết trên bằng cách sử dụng Visual Studio Code trên kênh YouTube của chúng tôi. Vui lòng ghé thăm kênh YouTube.