# 引言

首先我们知道 JS 中是没有并行,并发等概念的,这是因为 JS 是一门单线程的语言,其中的异步执行也是利用事件循环机制进行的,并不是严格意义上的异步。由于 JS 单线程的特性,使得 JS 在执行时如果遇到大量的任务就会使得过程运行缓慢。主渲染线程的延迟明显,使得用户体验较差.

# web-worker

web-worker 的作用就是用来缓解这一问题的

利用 web-worker, 我们可以利用浏览器新开辟一个进程,将需要大量执行的过程在这个进程中执行,然后将结果返回给我们的主进程即可.

# 使用示例

# worker.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .p{
      line-break: unset;
    }
  </style>
  <a id="link"></a>
    <p class="p">
      <%= sjdfl =%>
    </p>
</head>
<body>
  <script>
    const \u4e2d\u6587 = '这是转义之后的字符';
// 使用 webworker, 分担主线程的压力
// const worker = new Worker()
// 创建一个 worker
const worker = new Worker('./worker.js')
console.log(worker);
worker.postMessage('sdfj');
worker.postMessage({method:'echo',argus:[1,2,3,4]})
// 主线程关闭 worker
setTimeout(()=>{
worker.terminate()
// worker.postMessage('close')
},1000)
worker.addEventListener('message',(e)=>{
  console.log(e.data);
})
/**
 * 主线程监听 worker 错误
 */
worker.onerror=(e)=>{
  worker.terminate()
  console.error('worker错误');
}
/**
 * 直接转移数据的控制权
 */
// 创建 4 字节的缓冲区
let abfer = new ArrayBuffer(4);
// 创建 32 位整数数组作为视图,引用缓冲区
let tes = new Int32Array(abfer);
console.log(tes,'ArrayBuffer');
worker.postMessage(abfer,[abfer]); // 转交控制权,主线程不再存储
/**
 * 模拟文件下载功能
 */
const blob = new Blob(['文件下载']);
const link = document.getElementById('link');
link.href = window.URL.createObjectURL(blob);;
link.download = '测试文件.txt';
setTimeout(()=>{
  // link.click();
},2000)
/**
 * 创建 worker 线程加载 js 文件
 * !!必须指定 script 标签的 type 为浏览器不知道的类型
 */
// const blob1 = new Blob(document.getElementById('scriptDom').textContent);
// const url1 = new window.URL.createObjectURL(blob1);
// const worker2 = new Worker(url1);
/**
 * 使用 worker 线程,完成轮询
 */
// 创建 worker
function createWorker(f){
  const fnBlob = new Blob(['('+f.toString()+')()'])
  const fnUrl = window.URL.createObjectURL(fnBlob);
  return new Worker(fnUrl);
}
const fnWorker = createWorker((e)=>{
  let cache;
  // setInterval(()=>{
    fetch('/data').then(res=>{
      if(cache != res){
        console.log('变化了');
      }
    })
  // },1000)
});
  </script>
<script id="scriptDom" type="app/worker">
  console.log('我是被woeker加载的文件');
</script>
</body>
</html>

# worker.js

// 接受数据
console.log(self);
self.addEventListener('message',(e)=>{
    console.log(e.data);
    self.postMessage('我接受到了你的消息')
    if(e.data === 'close'){
        self.postMessage('听你的我关闭');
        self.close();
    }
},false)
// self.addEventListener('close',(e)=>{
//     console.log (' 关闭 ');
// })
/**
 * worker 内部加载脚本
 * 只能加载,不能获取其中内容
 */
importScripts('./main.js');

# serviceWorker

//serviceWorker 是基于事件驱动的。
//serviceWorker 安装事件
self.addEventListener('install',event=>{
    console.log(event,'安装事件');
    event.waitUntil(()=>{
        console.info('安装完成');
    })
})
//serviceWorker 激活事件(当安装完成之后就开始激活)
self.addEventListener('active',(event)=>{
    let cacheWhiteList = ['product-v2'];
    event.waitUntil(
        caches.keys().then(cacheNames=>{
            return Promise.all(
                cacheNames.map(cacheName=>{
                    if(cacheWhiteList.indexOf(cacheName) === -1){
                        return caches.delete(cacheName);
                    }
                })
            )
        })
    )
})
//serviceWorker 与网页的通信
self.addEventListener('active',(event)=>{
    event.waitUntil(
        self.clients.matchAll().then((client)=>{
            client.postMessage({
                msg:"Hello serviceWorker",
                source:"serviceWorker"
            })
        })
    )
})

# sharedWorker

//sharedWorker 示例
// ============ 1. 创建 sharedWorker(shared-worker.js) ============
// 这是一个独立的 worker 文件,需要在 HTTP 服务器环境下运行
// 因为浏览器对 file:// 协议的 SharedWorker 有安全限制
const ctx = self; // SharedWorker 的全局上下文
ctx.onconnect = function (e) {
  const port = e.ports[0];
  port.onmessage = function (event) {
    const { type, payload, id } = event.data;
    let response;
    switch (type) {
      case 'ping':
        response = { message: 'pong', timestamp: Date.now() };
        break;
      case 'broadcast':
        // 广播消息给所有连接的端口
        ctx.clients.forEach((client) => {
          client.postMessage({ type: 'broadcast', payload });
        });
        response = { success: true, clientCount: ctx.clients.length };
        break;
      case 'getClients':
        response = { clientCount: ctx.clients.length };
        break;
      default:
        response = { error: 'Unknown message type' };
    }
    port.postMessage({ id, response });
  };
};
// ============ 2. 主线程 使用 sharedWorker ============
//sharedWorker 和普通 worker 的核心区别:
// 1. 多个页面 / 标签页可以共享同一个 worker 实例
// 2. worker 可以通过端口与每个页面通信
// 3. worker 可以广播消息给所有连接的客户端
// 创建 SharedWorker 实例
const worker = new SharedWorker('./shared-worker.js', { name: 'my-shared-worker' });
// 获取通信端口
const port = worker.port;
// 生成唯一 ID 追踪响应
let requestId = 0;
const pendingRequests = new Map();
// 监听来自 worker 的消息
port.onmessage = function (event) {
  const { id, response } = event.data;
  const resolver = pendingRequests.get(id);
  if (resolver) {
    resolver(response);
    pendingRequests.delete(id);
  }
};
// 发送带回调的请求
function sendMessage(type, payload) {
  return new Promise((resolve) => {
    const id = ++requestId;
    pendingRequests.set(id, resolve);
    port.postMessage({ id, type, payload });
  });
}
// 启动端口
port.start();
// ============ 3. 示例用法 ============
// 3.1 ping-pong 测试
sendMessage('ping').then((res) => {
  console.log('ping result:', res);
  // { message: 'pong', timestamp: 1234567890 }
});
// 3.2 在多个标签页间广播消息
// 打开多个标签页,在一个标签页执行:
sendMessage('broadcast', 'Hello from Tab 1!').then((res) => {
  console.log('broadcast result:', res);
  // {success: true, clientCount: 3}  <- 假设有 3 个标签页连接
});
// 3.3 获取当前连接的客户端数量
sendMessage('getClients').then((res) => {
  console.log('connected clients:', res.clientCount);
});
// ============ 4. 关闭连接 ============
// 页面关闭时
window.addEventListener('beforeunload', () => {
  port.close();
  console.log('SharedWorker connection closed');
});
// ============ 5. 注意事项 ============
//- SharedWorker 需要通过 HTTP (S) 服务器访问(不能通过 file:// 协议)
//- 可以用 npx serve . 或 python -m http.server 启动本地服务器
//- Safari 对 SharedWorker 的支持相对有限,测试时建议用 Chrome
更新于 阅读次数 次

请我喝[茶]~( ̄▽ ̄)~*

dmq 微信支付

微信支付

dmq 支付宝

支付宝