Web Worker,启动!

274 阅读3分钟

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文件,与主线程通过postMessageonMessage进行通信。
  • 脚本加载:可以使用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.htmlworker.js位于同一目录下,并在支持Web Worker的浏览器中打开index.html文件来查看效果。