Web Workers的强大之处- JavaScript中的多线程
Web Workers 是一个浏览器API,允许JavaScript在一个单独的线程中并行执行任务。它使主线程能够继续运行而不被阻塞,从而保持用户界面的响应性。Web Worker在一个独立的全局上下文中运行,这意味着它有自己的JavaScript引擎实例,因此不能直接访问主线程的变量或函数。相反,Web Workers使用消息传递系统与主线程进行通信。
创建Web Worker: 要创建Web Worker,我们可以使用Worker构造函数。Worker构造函数以URL作为参数,该URL是worker脚本文件的路径。然而,由于我们希望将worker代码包含在HTML文件中,我们可以使用一个blob来创建worker代码。
语法:
const worker = new Worker('worker.js');
与Web Workers通信: 创建了Web Worker后,我们可以使用postMessage()方法和onmessage事件处理程序在主线程和工作线程之间发送和接收消息。
以下代码片段将一条消息从主线程发送给Web Worker:
// Create a new web worker
const myWorker = new Worker("worker.js");
// Send a message to the worker
myWorker.postMessage("Hello, worker!");
在这段代码片段中,我们创建了一个新的Web Worker,并使用postMessage()方法向其发送消息。为了接收来自Web Worker的消息,我们需要为 onmessage 事件添加一个事件监听器。以下是接收来自Web Worker消息的代码片段:
// Create a new web worker
const myWorker = new Worker("worker.js");
// Receive a message from the worker
myWorker.onmessage = function (event) {
console.log(event.data);
};
在这段代码中,我们创建了一个新的网页工作者,并为onmessage事件添加了一个事件监听器。当网页工作者向主线程发送消息时,onmessage事件处理程序被调用,并将消息记录到控制台。
示例1:(结合上述所有代码片段): 计算一个数字的阶乘,比如10。我们可以使用Web Worker在一个单独的线程中执行这个计算,像这样:
HTML
<!DOCTYPE html>
<html>
<head>
<title>Web Workers Example</title>
<style>
body {
text-align: center;
}
h1 {
color: green;
}
</style>
</head>
<body>
<h1>GeeksforGeeks</h1>
<h2>Web Workers Example</h2>
<p>
Calculate the factorial of 10 using a
web worker to prevent blocking the UI
thread.
</p>
<div id="result"></div>
<script>
const worker = new Worker(URL.createObjectURL(new Blob([
`
// Worker script
const factorial = (n) => {
if (n == 0 || n == 1) {
return 1n;
} else {
return BigInt(n) * factorial(BigInt(n) - 1n);
}
};
self.onmessage = (event) => {
const result = factorial(event.data);
self.postMessage(result.toString());
};`
], { type: "text/javascript" })));
worker.postMessage(10n);
worker.onmessage = (event) => {
const result = event.data;
document.getElementById("result").innerHTML
= `Factorial of 10 is ${result}`;
};
</script>
</body>
</html>
输出:
说明: 在这个例子中,我们通过实例化Worker类并使用包含worker代码的新Blob对象的URL来创建一个新的Web Worker。该worker的代码在一个匿名函数中定义,使用递归函数计算一个数的阶乘。worker使用self.onmessage事件监听从主线程发送的消息,计算输入数的阶乘,并使用self.postMessage方法将结果发送回主线程。
在主线程中,我们创建一个新的worker实例,并发送一个包含数字10n(n后缀表示这是一个BigInt值)的消息给它。一旦worker计算完成阶乘,它就会使用postMessage方法将结果发送回主线程。主线程在onmessage事件中接收到结果,并使用计算后的值更新结果div元素的HTML内容。
例子2: 这个例子打印出小于等于n的素数。该例子允许用户输入一个数字,然后使用web worker计算出小于等于该数字的所有素数。worker脚本检查每个数字是否为素数,并将所有素数的数组返回给主线程以在结果段落中显示。
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Web Worker Example</title>
<style>
body {
text-align: center;
}
h1 {
color: green;
}
</style>
</head>
<body>
<h1>GeeksforGeeks</h1>
<h2>Web Worker Example</h2>
<p>
This example shows how to use a web
worker to perform a long-running task
without blocking the main thread.
</p>
<p>
Enter a number below to find all prime
numbers up to that number.
</p>
<input type="number" id="num" min="1">
<button onclick="startWorker()">Start</button>
<button onclick="stopWorker()">Stop</button>
<p id="result"></p>
<script>
// Create a new worker
let worker;
function startWorker() {
const num = document.getElementById("num").value;
if (num === "") {
alert("Please enter a number");
return;
}
worker = new Worker("data:text/javascript;base64,"
+ btoa(workerScript));
// Send message to worker
worker.postMessage(num);
// Listen for message from worker
worker.onmessage = function (event) {
document.getElementById("result").innerHTML =
event.data.join(", ");
};
}
function stopWorker() {
worker.terminate();
}
// The script to be executed in the worker
const workerScript = `
function isPrime(num) {
if (num < 2) {
return false;
}
for (let i = 2; i < num; i++) {
if (num % i === 0) {
return false;
}
}
return true;
}
onmessage = function(event) {
const num = parseInt(event.data);
const primes = [];
for (let i = 2; i <= num; i++) {
if (isPrime(i)) {
primes.push(i);
}
}
postMessage(primes);
};`;
</script>
</body>
</html>
输出:
Web workers的好处:
- 在JavaScript中实现多线程
- 通过在单独的线程中执行计算密集型任务来提高性能
- 避免阻塞主线程,使用户体验更加响应
使用web workers的缺点:
- 内存消耗增加
- 主线程和worker之间的通信开销
- 总体而言,web workers是JavaScript语言的一项有价值的增加,在解决阻塞主线程问题方面提供了解决方案。通过利用web workers,开发人员可以创建更快、响应更快的Web应用程序,从而改善受众的用户体验。
结论: 重要的一点要注意的是,使用web workers也可能有缺点。由于workers是独立的执行线程,它们可能会增加应用程序的内存消耗。此外,主线程和workers之间的通信会引入开销,使应用程序变慢。因此,必须仔细考虑使用web workers,并且只在必要时使用它们。总之,Web workers是一个强大的工具,可以实现JavaScript的多线程,使我们能够执行计算密集型任务而不阻塞主线程。通过利用web workers,我们可以显著提高Web应用程序的性能,创造更快、更响应的用户体验。