Web Worker

Web worker

Web Worker 可以开启一个独立于 Web 应用程序主执行线程的后台线程,可以在独立线程中执行费时的处理任务,使主线程的运行不会被阻塞/放慢。
worker()构造函数接收一个参数,参数为一个具名的 JavaScript 文件,该文件包含需要在 worker 中运行的代码。不能在 worker 线程操作 DOM,或使用 window 对象中的某些方法和属性。

在主线程与 worker 之间传递的数据是通过深拷贝,而不是共享来完成的。

主线程和 worker 之间数据传递:
postMessage() 双方都使用该方法发送各自的消息
onmessage 使用该事件处理函数来响应消息

Worker 的类型:

  • 专用 Worker //var worker = new Worker(“./worker.js”);
  • 共享 Worker //var worker = new SharedWorker(“./sharedworker.js”);
  • Service Worker // navigator.serviceWorker.register(“./sw.js”)
专用 worker

一个专用 worker 仅能被生成它的脚本所使用。

//html页面主线程部分
 <body>
    <div>
      <input id="first" type="number" /> * <input id="second" type="number" /> =
      <input id="result" type="text" readonly />
      <button id="button">终止worker</button>
    </div>
    <script>
      if (window.Worker) {
        var worker = new Worker("./dedicatedworker.js");
        const first = document.querySelector("#first");
        const second = document.querySelector("#second");
        const result = document.querySelector("#result");
        const changeHandle = () => {
          const data = { first: first.value, second: second.value };
          worker.postMessage(data); //向worker传数据
        };
        first.onchange = changeHandle;
        second.onchange = changeHandle;
        //接收worker发送的数据
        worker.onmessage = function (e) {
          result.value = e.data;
        };

        //终止worker
        document.querySelector("#button").addEventListener("click", () => {
          worker.terminate();//终止worker
        });
      }
    </script>
  </body>
//dedicatedworker.js部分

//接收主线程的数据,数据在e.data中
onmessage = (e) => {
  const { first, second } = e.data;
  let res;
  if (first && second) {
    res = first * second;
  } else {
    res = "";
  }
  //将处理结果发送给主线程
  postMessage(res);
};

共享 worker

一个共享 worker 可以被多个脚本使用——即使这些脚本正在被不同的 window、iframe 或者 worker 访问。如果共享 worker 可以被多个浏览上下文调用,所有这些浏览上下文必须属于同源(相同的协议,主机和端口号)。
一个共享 worker 通信必须通过 port 对象供脚本与 worker 通信(在专用 worker 中这一部分是隐式进行的)。

使用 sharedworker 实现跨标签也通信:

//页面一
<body>
    <input type="text" name="" id="content">
    <button id="btn">发送信息</button>
    <script>
        const content = document.querySelector('#content');
        const btn = document.querySelector('#btn');

        // 创建一个 worker
        const worker = new SharedWorker('worker.js');

        btn.onclick = function(){
            worker.port.postMessage(content.value);
        }
    </script>
</body>
//页面二
<body>
    <script>
        const worker = new SharedWorker("worker.js");
        worker.port.start();
        worker.port.onmessage = function(e){
            if(e.data){
                console.log(`来自 worker 的数据:`,e.data);
            }
        }
        setInterval(function(){
            worker.port.postMessage("get");
        },1000)
    </script>
</body>

//worker.js内容

var data = ""; // 存储用户发送过来的信息
onconnect = function (e) {
  var port = e.ports[0];

  port.onmessage = function (e) {
    // 说明要将接收到数据返回给客户端
    if (e.data === "get") {
      port.postMessage(data);
      data = "";
    } else {
      data = e.data;
    }
  };
};

Service Worker

本质上充当 Web 应用程序、浏览器与网络之间的代理服务器。旨在创建有效的离线体验,它会拦截网络请求并根据网络是否可用采取适当的动作、更新来自服务器的资源。
Service worker 仅限在 HTTPS 上运行。为了促进本地开发,浏览器也认为 localhost 是一个安全的来源。

Service Worker 实际上是浏览器和服务器之间的代理服务器,它最大的特点是在页面中注册并安装成功后,运行于浏览器后台,不受页面刷新的影响,可以监听和截拦作用域范围内所有页面的 HTTP 请求

Service Worker 的目的在于离线缓存,转发请求和网络代理。

Service Worker 注册:navigator.serviceWorker.register
语法:navigator.serviceWorker.register(scriptURL,options)
scriptURL: service worker 脚本的 URL
options:{scope: ‘/’} 表示定义 service worker 注册范围的 url,即该 service worker 有效作用范围

使用 Service Worker 实现跨标签页通信:

//页面一
<body>
    <input type="text" name="" id="content">
    <button id="btn">发送数据</button>
    <script>
        const conetnt = document.querySelector("#content");
        // 注册 service worker
        navigator.serviceWorker.register('sw.js')
            .then(()=>{
                console.log("service worker 注册成功");
            });
        btn.onclick = function(){
            navigator.serviceWorker.controller.postMessage({
                value : content.value
            })
        }
    </script>
</body>

//页面二
<body>
    <script>
        // 注册 service worker
        navigator.serviceWorker.register('sw.js')
            .then(()=>{
                console.log("service worker 注册成功");
            });
        navigator.serviceWorker.onmessage = function({data}){
            console.log(data);
        }
    </script>
</body>
//在两个页面之间,相当于一个中转站
// 消息就会到达这里
self.addEventListener("message", async (event) => {
  // 首先获取到所有注册了 service worker 的客户端
  const clients = await self.clients.matchAll();
  clients.forEach(function (client) {
    client.postMessage(event.data.value);
  });
});

Service Worker 实现缓存:

const putInCache = async (request, response) => {
  const cache = await caches.open("v1");
  await cache.put(request, response);
};

const cacheFirst = async ({ request, preloadResponsePromise, fallbackUrl }) => {
  // 首先,尝试从缓存中获取资源
  const responseFromCache = await caches.match(request);
  if (responseFromCache) {
    return responseFromCache;
  }

  // 然后尝试从网络中获取资源
  try {
    const responseFromNetwork = await fetch(request);
    // 响应可能会被使用
    // 我们需要将它的拷贝放入缓存
    // 然后再返回该响应
    putInCache(request, responseFromNetwork.clone());
    return responseFromNetwork;
  } catch (error) {
    const fallbackResponse = await caches.match(fallbackUrl);
    if (fallbackResponse) {
      return fallbackResponse;
    }
    // 当回落的响应也不可用时,
    // 我们便无能为力了,但我们始终需要
    // 返回 Response 对象
    return new Response("Network error happened", {
      status: 408,
      headers: { "Content-Type": "text/plain" },
    });
  }
};

self.addEventListener("fetch", (event) => {
  event.respondWith(
    cacheFirst({
      request: event.request,
      fallbackUrl: "/gallery/myLittleVader.jpg",
    })
  );
});
<think>好的,我现在需要处理用户关于WebWorker的问题。用户想了解如何在JavaScript中使用WebWorker,或者解决常见的相关问题。首先,我得回忆一下WebWorker的基本概念和用法,确保信息准确。 首先,WebWorker允许在后台线程运行脚本,避免阻塞主线程。这点很重要,尤其是在处理复杂计算时。我需要分步骤说明如何创建和使用WebWorker,包括实例化Worker对象、消息传递和终止Worker。然后,可能还要提到同源策略的限制,以及如何应对。 接下来是常见问题及解决方法。比如DOM操作的问题,因为WebWorker不能访问DOM,所以需要提醒用户通过消息传递让主线程处理。然后,错误处理,比如监听error事件。加载外部脚本的问题,可能需要使用importScripts方法。还有兼容性检查,避免在不支持的环境中使用。 然后,性能优化方面,比如避免频繁通信,因为序列化和反序列化数据有开销。内存管理方面,及时终止Worker防止内存泄漏。还要提到共享内存和SharedArrayBuffer,但需要注意线程安全。 最后,生成相关问题,帮助用户进一步学习。比如应用场景、数据通信方法、替代方案等。需要确保问题覆盖用户可能关心的其他方面。 在回答过程中,要遵循系统指令,使用正确的中文,数学公式用$...$,独立公式用$$...$$。不过这个问题可能涉及代码较多,但用户提供的引用是关于Puppeteer的,可能和WebWorker无关,但需要检查是否有必要引用。不过用户给的引用[^1]是关于Chromium命令行参数的,可能不相关,但系统要求引用标识,所以可能需要找到合适的地方插入。不过当前回答可能没有直接引用到相关内容,可能需要忽略或寻找相关点。不过根据用户提供的引用内容,可能无法直接关联到WebWorker,所以可能不需要引用,但系统指令要求引用标识,可能需要调整。或者用户可能误放了引用,需要按实际情况处理。这里可能需要忽略该引用,或者如果有相关内容的话才添加。 检查是否有必要引用用户提供的链接,可能不需要,但根据系统指令,必须在回答中引用的段落末尾添加引用标识。所以需要找到合适的位置添加。比如在提到兼容性时,可能可以提到某些浏览器设置可能需要调整,类似引用中的Chromium参数,但可能比较牵强。或者可能用户提供的引用是示例,实际回答中需要引用其他内容,但用户没有提供其他资料,所以可能无法正确引用。这种情况下,可能需要忽略引用,但系统指令要求必须添加。这里可能需要灵活处理,或者在回答末尾添加引用说明,但用户提供的引用内容是关于Puppeteer的,可能无法关联。可能存在矛盾,需要按照实际情况处理。或许用户希望引用的内容是关于WebWorker的,但实际提供的引用是关于Chromium命令行开关的,可能是个错误。这种情况下,可能需要按照系统指令,在回答中的某个段落末尾添加引用标识,即使内容不相关。例如在提到兼容性检查时,可以添加引用,尽管内容不匹配。或者可能用户提供的引用有误,需要按实际情况处理。或者可能系统示例中的引用是示例,实际回答中需要根据用户提供的引用添加。这里可能需要将引用放在某个相关的位置,比如在讨论WebWorker的兼容性或浏览器设置时,引用提供的链接,说明如何调整浏览器参数,但可能关联性不大。例如,在提到某些浏览器可能需要特定设置才能使用WebWorker,可以添加引用,但用户提供的引用是关于忽略--enable-automation参数的解决方案。这可能不太相关,但根据系统指令,必须添加引用,所以可能需要找到一个相关点。或者可能在讨论WebWorker的调试时,提到使用开发者工具,可能需要引用相关资源,但用户提供的引用是关于Chromium命令行参数的,可能涉及启动参数,比如在调试时可能需要禁用某些安全策略,可以参考该链接中的参数设置。例如,如果WebWorker在本地文件系统中运行时遇到问题(由于同源策略),可能需要通过命令行参数启动浏览器,这时可以引用该链接。因此,在讨论同源策略限制时,可以添加引用,例如提到跨域问题可能需要调整浏览器启动参数,具体可参考相关资源[^1]。这样就能合理插入引用。 综上,回答结构大致如下: 1. WebWorker基本用法:创建、通信、终止。 2. 常见问题及解决方法:DOM操作、错误处理、外部脚本加载、兼容性。 3. 性能优化内存管理。 4. 相关问题生成。 5. 在讨论同源策略或浏览器设置时,插入引用。</think>### WebWorker的用法常见问题解决 #### 1. WebWorker基本用法 WebWorker允许在后台线程执行脚本,避免阻塞主线程。使用步骤如下: **a. 创建Worker文件** 新建一个独立的JavaScript文件(如`worker.js`),编写需要在后台运行的代码: ```javascript // worker.js self.onmessage = function(e) { const result = e.data * 2; // 示例:简单计算 self.postMessage(result); }; ``` **b. 主线程中实例化Worker** 在主线程中通过`new Worker()`创建Worker实例,并定义消息接收和错误处理: ```javascript // 主线程代码 const worker = new Worker('worker.js'); // 发送数据到Worker worker.postMessage(10); // 接收Worker返回的结果 worker.onmessage = function(e) { console.log('结果:', e.data); // 输出:20 }; // 错误处理 worker.onerror = function(e) { console.error('Worker错误:', e.message); }; // 终止Worker // worker.terminate(); ``` **注意事项**: - **同源策略**:Worker脚本必须主线程同源,否则会触发安全错误。若需跨域加载,可通过`Blob`或调整服务器CORS策略实现。 - **作用域限制**:Worker无法访问`DOM`、`window`或`document`对象。 --- #### 2. 常见问题解决方案 **问题1:Worker中无法操作DOM** **原因**:Worker运行在独立线程,主线程环境隔离。 **解决**:通过`postMessage`将计算结果传回主线程,由主线程更新DOM。 --- **问题2:Worker脚本加载失败** **错误示例**:`Uncaught DOMException: Failed to construct 'Worker'` **解决**: 1. 检查文件路径是否正确。 2. 确保服务器配置允许加载Worker脚本(如MIME类型为`application/javascript`)。 --- **问题3:数据序列化限制** **示例错误**:传递无法序列化的对象(如函数)会触发`DataCloneError`。 **解决**:仅传递简单数据(如JSON、`ArrayBuffer`)或使用结构化克隆算法支持的类型。 --- **问题4:兼容性问题** **场景**:低版本浏览器(如IE)不支持WebWorker。 **解决**: ```javascript if (typeof Worker !== 'undefined') { // 使用WebWorker } else { // 降级方案:在主线程处理或提示不支持 } ``` --- #### 3. 性能优化内存管理 - **减少通信频率**:批量传输数据,避免频繁`postMessage`调用。 - **终止闲置Worker**:调用`worker.terminate()`释放资源。 - **使用共享内存**:通过`SharedArrayBuffer`实现高效数据共享(需注意线程安全)。 --- #### 4. 调试技巧 - 在Chrome开发者工具中,通过`Sources > Threads`查看Worker线程。 - 添加`debugger`语句到Worker脚本,断点调试。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值