web worker

1.简介

当网页运行JavaScript代码时,它是在一个单一的线程中执行的,这意味着在执行某些长时间运行的任务时,会导致界面卡顿或不响应。为了解决这个问题,HTML5引入了Web Worker API,允许在后台运行脚本,以便执行计算密集型任务,而不会阻塞用户界面。

Web Worker具有以下特点:

  1. 多线程执行: Web Worker允许在单独的线程中运行JavaScript代码,这使得可以在后台执行耗时任务,而不会影响到主线程的运行,从而保持用户界面的流畅性和响应性。
  2. 独立于主线程: Web Worker运行在与主页面代码分离的独立线程中,它们无法访问主线程的DOM,也无法直接操作页面上的元素。这种隔离性确保了主线程与Web Worker之间的互不干扰,避免了死锁和竞态条件等问题。
  3. 通信机制: 主线程与Web Worker之间可以通过消息传递进行通信。主线程使用postMessage()方法发送消息给Web Worker,而Web Worker内部通过self.onmessage监听消息,然后执行相应的操作。Web Worker也可以通过postMessage()方法将结果或其他信息发送回主线程。
  4. 受限环境: 由于Web Worker无法访问主线程的DOM和全局变量,它们在执行环境上是受限的,例如无法直接操作页面上的元素或使用某些浏览器特定的API。这样的限制使得Web Worker主要用于纯计算任务,而不是处理用户界面。

2.示例代码

以下是一个简单的Web Worker示例代码,该示例将计算斐波那契数列的前n项:

当用户在输入框中输入要计算的斐波那契数列的项数并点击“开始计算”按钮时,将会触发startWorker()函数。该函数首先检查浏览器是否支持Web Worker,然后创建一个新的Web Worker实例并将输入值传递给它。Web Worker在计算完斐波那契数列后,将结果发送回主页面,并更新页面上的结果部分。

HTML文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Web Worker 示例</title>
</head>
<body>
<h1>计算斐波那契数列</h1>
<p>请输入要计算的斐波那契数列的项数:</p>
<input type="number" id="input" value="10">
<button onclick="startWorker()">开始计算</button>
<p id="result"></p>

<script>
function startWorker() {
var input = document.getElementById("input").value;
if(typeof(Worker) !== "undefined") {
if(typeof(w) == "undefined") {
w = new Worker("worker.js");
}
w.postMessage(input);
w.onmessage = function(event) {
document.getElementById("result").innerHTML = "结果:" + event.data;
};
} else {
document.getElementById("result").innerHTML = "抱歉,您的浏览器不支持 Web Workers。";
}
}
</script>
</body>
</html>

worker.js:(在这里定义了web worker的工作内容)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function calculateFibonacci(n) {
var a = 0, b = 1, temp;
for (var i = 0; i < n; i++) {
temp = a;
a = a + b;
b = temp;
}
return a;
}

self.onmessage = function(event) {
var result = calculateFibonacci(event.data);
self.postMessage(result);
};

self.onmessage在Web Worker内部会在接收到消息时被调用。当主线程通过worker.postMessage()向Web Worker发送消息时,Web Worker内部的self.onmessage会被触发,并且传入一个事件对象作为参数,该事件对象包含发送的消息在event.data中。

在上述示例中,当Web Worker收到主线程发送的要计算的斐波那契数列项数时,它会执行计算,并将结果通过self.postMessage()发送回主线程。主线程接收到这个消息后,会触发在w.onmessage中定义的回调函数,从而处理来自Web Worker的结果。

简单来说就是主线程向子线程postMessage()会触发子线程的onmessage。同样的子线程向主线程postMessage()也会触发主线程的onmessage。显而易见postMessage的参数会作为被触发的onmessage的参数执行相应动作。

3.总结

  1. web worker是html5中提出来的为了解决单线程阻塞问题的一个新API。
  2. 可以使用该API创建多个子线程。子线程完全受主线程控制并且不能操作DOM。
  3. 子线程和主线程之间使用postMessage和onmessage进行通信。