web worker 是什么

用官方的话说: Web Worker 是一种在浏览器中运行的 JavaScript 脚本,可以在独立的线程中今执行,与主线程并行工作,提供了一种在后台执行复杂计算或处理耗时操作的方式,而不会堵塞主线程的执行。

用我自己的理解:就是“开小灶”,众所周知,Js是一种单线程语言,在传统的 Js 环境中,所有代码都运行在一个主线程中,包括处理用户界面,js代码执行和网络请求。当执行耗时操作时,就会导致用户页面的卡顿和不响应。而 Web Worker 的出现允许让开发者将耗时操作放在独立的线程中执行进而不会堵塞主线程,它还可以与主线程进行通信,通过信息传递机制来交换数据和结果。总的来说,Web Worker就是在浏览器“空闲”的时候开出一条独立于主线程的新线程,并通过“某种手段”实现与主线程通信,在不堵塞主线程的同时还提高了用户的体验。

使用

Web Worker 面对解决大文件上传的步骤

  • 创建一个Web Worker:在主线程上使用new Worker()构造函数创建一个Web Worker示例。指定Web Worker脚本的URL,该脚本在后台执行.
  • Web Worker脚本中处理文件上传处理:在Web Worker脚本中,使用onmessage事件监听主线程发送的消息。当收到上传文件的数据时,Web Worker可以将文件数据分块处理,并将每个块上传到服务器.
  • 与主线程进行通信:Web Worker可以使用postMessage()方法将处理结果发送回主线程。eg: 可以发送上传进度、成功或失败的信息.
  • 监听Web Worker的消息:在主线程中,可以使用onmessage事件监听Web Worker发送的消息,根据接收到的消息,可以更新上传进度、显示成功或失败的消息等.

关键代码

  • 创建FileUploader组件
 1import React, { useState } from "react";
 2
 3const FileUploader = () => {
 4  const [progress, setProgress] = useState(0);
 5
 6  const handleFileUpload = () => {
 7    const worker = new Worker("worker.js");
 8
 9    worker.onmessage = (event) => {
10      const { type, payload } = event.data;
11
12      if (type === "progress") {
13        setProgress(payload);
14      } else if (type === "success") {
15        console.log("File upload successful");
16        
17      } else if (type === "error") {
18        console.error("File upload failed");
19        
20      }
21    };
22
23    
24    const file = document.getElementById("inputFile").files[0];
25
26    
27    worker.postMessage(file);
28  };
29
30  return (
31    <div>
32      <input type="file" id="inputFile" />
33      <button onClick={handleFileUpload}>上传文件</button>
34      <div>上传进度:{progress}%</div>
35    </div>
36  );
37};
38
39export default FileUploader;
  • 创建Web Worker脚本
 1self.onmessage = (event) => {
 2  const file = event.data;
 3  const CHUNK_SIZE = 1024 * 1024; 
 4
 5  const totalChunks = Math.ceil(file.size / CHUNK_SIZE);
 6  let uploadedChunks = 0;
 7
 8  const uploadChunk = (chunk) => {
 9    
10    setTimeout(() => {
11      uploadedChunks++;
12      const progress = Math.floor((uploadedChunks / totalChunks) * 100);
13      self.postMessage({ type: "progress", payload: progress });
14
15      if (uploadedChunks === totalChunks) {
16        self.postMessage({ type: "success" });
17      } else {
18        
19        uploadChunk();
20      }
21    }, 1000);
22  };
23
24  
25  uploadChunk();
26};

上面的代码示例中,FileUploader组件包含一个文件选择框和一个上传按钮,当点击上传按钮,通过new Worker()创建一个Wrb Worker示例,将文件数据传递给Web Worker。Web Worker在后台执行文件上传逻辑,并通过postMessage()方法将上传进度和结果发送回到主线程。主线程通过监听Web Worker的消息来更新上传进度,并根据上传结果执行相应的逻辑.

  • webpack 配置相关插件

    使用worker-loader配置

     1  module.export = {
     2      
     3      module:{
     4          rules:[
     5              {
     6                  test:/\.worker\.js$/,
     7                  use:{ loader: 'worker-loader' }
     8              }
     9          ]
    10      }
    11  }
    

    上面配置项将匹配以.worker.js结尾的文件,并使用worker-loader来处理。在代码中,可以通过new Worker()语法来创建Web Worker示例.

    使用inline-loader配置

     1 module.export = {
     2      
     3      module:{
     4          rules:[
     5              {
     6                  test:/\.worker\.js$/,
     7                  use:[
     8                  { loader: 'worker-loader' },
     9                  { loader: 'inline-loader' }
    10                  ]
    11              }
    12          ]
    13      }
    14  }
    

    上述配置将使用worker-loader加载Web Worker脚本,并使用inline-loader内联脚本。在代码中,可以直接使用import语法引入Web Worker脚本.

注意点

  • Web Worker不能直接访问DOM,因此在处理文件上传时,可能需要将文件数据转换为ArrayBufferBlob等格式进行处理.
  • Web Worker有两种类型:Dedicated WorkerShared Worker。Dedicated Worker只能被创建它的脚本所使用,而Share Worker可以被多个脚本共享。无论是哪种类型的Web Worker,它们都有自己的全局作用域,可以执行JavaScript代码,并且可以通过postMessage()方法发送消息给创建它们的上下文,并通过onmessage时间监听来接受消息.
  • 在实际使用Web Worker进行大文件上传之前,建议进行充分的测试和性能优化。可以模拟各种网络条件和文件大小,评估上传速度、内存使用和用户体验,并根据测试结果进行优化.
  • 如果需要支持断点续传功能,可以在上传过程中记录已上传的块,以便在上传中断后能够从上次中断的地方继续上传。这可以通过将已上传的块信息保存在浏览器的本地存储或服务器端进行记录来实现。

待续

个人笔记记录 2021 ~ 2025