Web Worker提出的背景
众所周知,JavaScript在处理任务时分为同步和异步两种模式,这种设计巧妙地缓解了主线程被阻塞的问题。然而,这并不意味着所有阻塞情况都已得到解决。
设想一下以下情景:
- 当同步任务运行时遇到类似
while(1)
的死循环,程序将会怎样? - 如果必须执行一个计算量极大的同步任务,又该如何应对?
这两种情形都会造成同步任务的阻塞。为了应对这些挑战,HTML5引入了Web Worker的概念,目的就是为了解决同步任务可能导致的阻塞问题。通过Web Worker,我们可以在后台线程中运行JavaScript代码,从而实现主线程的解放,保证用户界面的流畅响应。
Web Worker概述
HTML5引入的Web Worker技术为Web应用程序提供了一种在后台处理任务的能力。这项技术支持多线程处理,使得Web应用能够充分利用多核CPU的性能,将那些耗时且资源密集的任务交由Web Worker执行,从而避免了页面阻塞、延迟或冻结等不良用户体验。 通过使用Web Worker API,你可以在后台创建并运行线程,将长时间运行的任务交给后台执行,而不会对当前页面造成任何影响。
特点
- 通信机制:Worker是一个JavaScript文件,与主线程通过
postMessage
和onMessage
进行通信。 - 脚本加载:可以使用
Worker
内部的importScripts(url)
方法加载其他JavaScript文件。 - 功能支持:支持定时器等方法,以及使用XMLHttpRequest进行异步请求。
- 核心对象使用:可以使用JavaScript的核心对象。
局限性
- DOM访问限制:不能访问DOM。
- 跨域限制:不能跨域加载JavaScript文件。
- 数据加载效率:有些情况下,使用Web Worker加载数据效率不如JSONP和AJAX。当然要看具体场景。
兼容性
Web Worker在主流浏览器中有较好的兼容性。
属性和方法
- self:用于表示当前线程的作用域。
- postMessage():向创建线程的原始窗口发送消息。
- onMessage():用于获取和处理接收到的消息的事件监听器。
- importScripts(...urls):在Worker内部加载其他JavaScript脚本文件的方法,支持同时导入多个脚本。
Worker 使用实例
背景:index.html中有一个费时间很长的同步任务(计算斐波那契前30项)。现在需要new 一个worker。
在这个示例中,当用户点击“开始 Worker 计算”按钮时,主线程将创建一个新的Worker
实例,并开始监听来自worker.js
的消息。worker.js
接收到来自主线程的启动信号后,会执行一个耗时的计算(在这个例子中是计算斐波那契数列的第30项),然后将计算结果发送回主线程。主线程接收到消息后,更新按钮的文本显示计算结果。
index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Web Worker 示例</title>
</head>
<body>
<h1>Web Worker 计算</h1>
<button id="startWorker">开始 Worker 计算</button>
<script>
// 检查浏览器是否支持 Web Worker
if (typeof (Worker) !== "undefined") {
// 创建一个新的 worker 实例
const worker = new Worker("worker.js");
// 监听来自 worker 的消息
worker.onmessage = function (event) {
document.getElementById("startWorker").innerText = "计算完成:" + event.data;
};
// 点击按钮时,发送消息给 worker
document.getElementById("startWorker").addEventListener("click", function () {
worker.postMessage("开始计算");
});
} else {
document.getElementById("startWorker").innerText = "抱歉,您的浏览器不支持 Web Worker";
}
</script>
</body>
</html>
worker.js
// 监听从主线程发送的消息
self.onmessage = function (event) {
// 进行一些计算(例如:斐波那契数列)
function fibonacci(n) {
return n < 1 ? 0 : n <= 2 ? 1 : fibonacci(n - 1) + fibonacci(n - 2);
}
// 计算第 30 项的斐波那契数(这是一个耗时的操作)
const result = fibonacci(30);
// 将结果发送回主线程
self.postMessage(result);
};
请确保
index.html
和worker.js
位于同一目录下,并在支持Web Worker的浏览器中打开index.html
文件来查看效果。