Web Worker简介和使用

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 = fibonacciArray(n);
  // 将结果发送回主线程
  postMessage(result);
};
// 计算斐波那契数列
function fibonacciArray(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缺陷
  1. 无法直接访问 DOM:由于 Web Worker 运行在独立的线程中,不能直接访问主线程中的 DOM,因此需要使用特殊的方式进行通信,如 postMessage() 方法。

  2. 无法访问主线程中的 JavaScript 对象:Web Worker 独立运行在一个线程中,无法直接访问主线程中的 JavaScript 对象,需要使用序列化和反序列化等技术进行数据传递。

  3. 无法加载本地文件:Web Worker 只能通过网络加载 JavaScript 文件,无法直接加载本地文件。

  4. 无法执行同步操作:Web Worker 无法执行同步操作,如读取文件或等待用户的输入等,因为同步操作会阻塞 Web Worker 的线程。

  5. 不支持所有浏览器: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 的一些应用场景:

  1. 图像处理:在 Web 应用程序中,经常需要对图片进行处理、缩放、剪裁等操作。这些操作可能会消耗大量的 CPU 时间和内存资源,导致页面变卡。使用 Web Worker 可以将这些计算密集型任务放到后台线程中执行,避免阻塞主线程。
  2. 数据计算:对于大规模的数据集,需要进行复杂的计算和数据分析,例如数据挖掘、机器学习、人工智能等。这些任务需要大量的计算资源和时间,使用 Web Worker 可以将计算任务分散到多个线程中,加快计算速度。
  3. 后台请求:在 Web 应用程序中,可能需要进行一些后台请求和数据处理,例如与服务器进行交互、读写文件等。使用 Web Worker 可以将这些任务放到后台线程中执行,避免阻塞主线程,提高应用程序的性能和响应速度。
  4. 多媒体处理:在 Web 应用程序中,经常需要对音频、视频等多媒体资源进行处理和转码,这些任务需要大量的计算资源和时间。使用 Web Worker 可以将这些任务放到后台线程中执行,避免阻塞主线程。

需要注意的是,Web Worker 并不是适用于所有场景的解决方案。对于一些简单的任务,使用 Web Worker 可能会增加代码复杂度,并且可能会带来额外的开销和性能问题。因此,在应用 Web Worker 时需要根据具体情况进行评估和选择。

猜你喜欢

转载自blog.csdn.net/weixin_44380380/article/details/130552704