1、Web Worker简介
javascript 是一种单线程语言,这意味着在一个页面中,所有的 JavaScript 代码都在同一个线程中运行。在单线程模型中,所有任务都是按顺序执行的,如果某个任务需要花费较长时间才能完成,它将阻塞其他任务的执行。HTML5 引入了 Web Workers技术,允许在浏览器中创建多个 JavaScript 线程,以便在后台执行计算密集型任务,从而避免阻塞主线程。Web Worker 是一个独立的 JavaScript 程序,它运行在与主线程不同的上下文中,并且与主线程是完全独立的, 可以运行长时间运算、处理大量数据或与服务器通信等任务,而不会阻塞页面的用户界面。
下面是 Web Worker 的几个优点:
-
提高页面性能:Web Worker 可以在后台线程中执行一些计算密集型或者耗时的操作,如数据处理、图像处理等,而不会占用主线程,从而避免了页面卡顿或者卡死的情况,提高了页面的性能和响应速度。
-
可以处理大规模数据:Web Worker 可以处理大规模的数据,因为它们在单独的线程中运行,不会影响主线程的运行,可以更高效地处理大规模的数据,提高了代码的效率和可扩展性。
-
可以使代码更加模块化:使用 Web Worker,可以将代码分割成多个模块,分别运行在不同的线程中,从而使得代码更加模块化,可维护性和可读性更强。
-
支持多线程:Web Worker 支持多线程,因此可以利用多核处理器的优势,提高代码的运行效率。
2、Web Worker的创建和使用
2.1 创建 Worker
在主线程中使用new Worker()构造函数来创建一个新的Worker对象,例如:
const worker = new Worker('worker.js');
这里的 worker.js
是一个独立的 JavaScript 文件,它将作为 Worker 的入口点。当创建 Worker 实例时,浏览器会将 worker.js
文件加载到一个独立的执行环境中,并开始运行它。
2.2 发送消息
以使用Worker对象的postMessage()方法向工作线程(worker.js)发送消息。例如:
worker.postMessage('Hello, worker!');
2.3 在工作线程(worker.js)中处理消息
在工作线程worker.js中,您可以使用onmessage事件监听器来接收来自主线程的消息,并使用postMessage()方法向主线程发送消息。例如:
onmessage = function(e) {
console.log('Message received from main thread:', e.data);
postMessage('Hello, main thread!');
}
这里的onmessage函数将在主线程发送消息时被调用,并将“Hello, main thread!”发送回主线程。
2.4 监听消息事件
在主线程中,可以使用onmessage事件监听器来接收来自工作线程的消息。例如:
Worker.onmessage = function(e) {
console.log('Message received from worker:', e.data);
}
2.5 Web Worker 的关闭
当你使用 Web Worker 时,它会占用一定的系统资源,如内存等。如果你创建了太多的 Worker,或者没有关闭它们,会导致系统资源的消耗,从而影响整个应用程序的性能。因此,为了避免资源泄漏和提高系统性能,我们应该在不再需要使用 Worker 的时候及时关闭它们。可以使用 Worker.terminate() 方法来关闭一个 Web Worker。
// 关闭Web Worker
worker.terminate();
2.6 worker.js文件加载引用
-
使用在html中引用 worker.js文件
<!-- 将worker.js文件包含在HTML中 --> <script src="worker.js"></script>
-
在javascript代码中直接引用
<!-- worker.js和主程序在同一文件夹下 --> const worker = new Worker('worker.js'); <!-- worker.js和主程序不在同一文件夹下 --> const worker = new Worker('../resource/fundids/js/worker_diff.js'); 3
-
worker.js中加载其他JavaScript代码
在Web Worker中,您不能直接访问页面中的DOM元素和JavaScript对象。如果您的Web Worker需要访问其他JavaScript代码,您可以使用importScripts()方法加载它们。importScripts()方法可以接受一个或多个参数,这些参数是需要加载的JavaScript文件的URL。在加载这些文件时,它们将立即被执行,并且在Web Worker的全局作用域中定义的所有变量和函数都将在Web Worker中可用。以下是一个示例,演示了如何在Web Worker中使用importScripts()方法加载其他JavaScript代码:
// 在这里可以使用在file1.js和file2.js中定义的变量和函数 importScripts("file1.js", "file2.js");
2.5 使用Web Worker实例
<!DOCTYPE html>
<html>
<head>
<title>Web Worker 斐波那契数列</title>
<script>
// 创建一个新的 Web Worker,指定 worker.js 文件作为代码文件
const worker = new Worker('worker.js');
// 向 Web Worker 发送一个消息
worker.postMessage(100);
// 监听 Web Worker 返回的结果
worker.onmessage = function(event) {
console.log('斐波那契数列:', event.data);
var resultElement = document.getElementById("result");
resultElement.innerHTML += "<span>"+event.data+"</span>";
};
</script>
</head>
<body>
<h1>Web Worker Example</h1>
<div id="result"></div>
</body>
</html>
在 worker.js 文件中,我们可以实现计算斐波那契数列的代码:
// 监听来自主线程的消息
onmessage = function(event) {
const n = event.data;
var result = fibona***iArray(n);
// 将结果发送回主线程
postMessage(result);
};
// 计算斐波那契数列
function fibona***iArray(n) {
var fib = [1, 1]; // 前两个数字是1
for (var i = 2; i < n; i++) {
fib[i] = fib[i-1] + fib[i-2]; // 计算下一个数字并添加到数组中
}
return fib;
}
在这个示例中,我们使用了一个 Web Worker 来计算斐波那契数列。当主线程向 Web Worker 发送一个消息时,Web Worker 开始计算斐波那契数列,并将结果发送回主线程。由于计算斐波那契数列可能需要一些时间,因此使用 Web Worker 可以避免阻塞主线程,从而提高页面性能和用户体验。
3、web worker缺陷
-
无法直接访问 DOM:由于 Web Worker 运行在独立的线程中,不能直接访问主线程中的 DOM,因此需要使用特殊的方式进行通信,如 postMessage() 方法。
-
无法访问主线程中的 JavaScript 对象:Web Worker 独立运行在一个线程中,无法直接访问主线程中的 JavaScript 对象,需要使用序列化和反序列化等技术进行数据传递。
-
无法加载本地文件:Web Worker 只能通过网络加载 JavaScript 文件,无法直接加载本地文件。
-
无法执行同步操作:Web Worker 无法执行同步操作,如读取文件或等待用户的输入等,因为同步操作会阻塞 Web Worker 的线程。
-
不支持所有浏览器:Web Worker 不是所有浏览器都支持,尤其是一些旧版的浏览器可能不支持 Web Worker。
if (typeof(Worker) !== "undefined") { // 支持webworker }
4、Web Worker与后端传输数据
Web Worker 不能直接访问主线程中的 DOM。这意味着 Web Worker 不能直接操作页面的 HTML 元素或修改浏览器的 URL。但是,Web Worker 可以使用 XMLHTTPRequest 和 Fetch API 等技术从服务器获取数据,并通过消息传递机制将数据发送给主线程。
4.1 使用XMLHttpRequest
// 监听从主线程发送来的消息
onmessage = function(event) {
var data = event.data;
var newData = [];
for (var i = 0; i < data.length; i++) {
_add(data[i]);
};
};
function _add(d,flag) {
var num1 = d.num1;
var num2 = d.num2;
var id = d.id;
// 创建 XMLHttpRequest 对象
var xhr = new XMLHttpRequest();
// 监听请求状态变化事件
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) { // 请求成功
result = {"id":id, "num1":num1, "num2":num2, "result":xhr.responseText};
postMessage(result);
}
};
// 发送 AJAX 请求
xhr.open("POST", "/test/WebWorkers/add_ajax.tsl", true); // 打开请求连接
// xhr.setRequestHeader("Content-type", "application/json"); // 设置请求头
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
// var data = {dowhat:'add', num1:num1, num2:num2}; // 定义要发送的数据并转换为 JSON 字符串
// xhr.send(JSON.stringify(data)); // 发送数据
var data = new URLSearchParams();
data.append("num1",num1);
data.append("num2",num2);
xhr.send(data); // 发送数据
}
4.2 Fetch API
function _add2(d){
var num1 = d.num1;
var num2 = d.num2;
var id = d.id;
//var data = new URLSearchParams();
var formData = new FormData();
formData.append("num1",num1);
formData.append("num2",num2);
fetch("/test/WebWorkers/add_ajax.tsl", {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
result = {"id":id, "num1":num1, "num2":num2, "result":data};
postMessage(result);
})
.catch(error => console.error(error))
}
FormData是一种用于处理表单数据的JavaScript API,它可以通过XMLHttpRequest或fetch()方法发送表单数据到后端服务器。FormData对象包含一个键值对列表,可以用于构建表单数据。可以使用FormData对象的append()方法向FormData对象添加键值对。
如上使用了FormData()以表单的形式提交数据,后端即可直接Q(“name”)获取数据,如果提交不同格式的数据,如json串等,当前后端获取前端参数的方法可能不支持。
6、应用场景
Web Worker 的一些应用场景:
- 图像处理:在 Web 应用程序中,经常需要对图片进行处理、缩放、剪裁等操作。这些操作可能会消耗大量的 CPU 时间和内存资源,导致页面变卡。使用 Web Worker 可以将这些计算密集型任务放到后台线程中执行,避免阻塞主线程。
- 数据计算:对于大规模的数据集,需要进行复杂的计算和数据分析,例如数据挖掘、机器学习、人工智能等。这些任务需要大量的计算资源和时间,使用 Web Worker 可以将计算任务分散到多个线程中,加快计算速度。
- 后台请求:在 Web 应用程序中,可能需要进行一些后台请求和数据处理,例如与服务器进行交互、读写文件等。使用 Web Worker 可以将这些任务放到后台线程中执行,避免阻塞主线程,提高应用程序的性能和响应速度。
- 多媒体处理:在 Web 应用程序中,经常需要对音频、视频等多媒体资源进行处理和转码,这些任务需要大量的计算资源和时间。使用 Web Worker 可以将这些任务放到后台线程中执行,避免阻塞主线程。
需要注意的是,Web Worker 并不是适用于所有场景的解决方案。对于一些简单的任务,使用 Web Worker 可能会增加代码复杂度,并且可能会带来额外的开销和性能问题。因此,在应用 Web Worker 时需要根据具体情况进行评估和选择。