惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园_首页
Y
Y Combinator Blog
Engineering at Meta
Engineering at Meta
D
Docker
GbyAI
GbyAI
aimingoo的专栏
aimingoo的专栏
大猫的无限游戏
大猫的无限游戏
腾讯CDC
P
Proofpoint News Feed
A
About on SuperTechFans
WordPress大学
WordPress大学
Stack Overflow Blog
Stack Overflow Blog
Google DeepMind News
Google DeepMind News
C
Check Point Blog
Microsoft Security Blog
Microsoft Security Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
L
LangChain Blog
MyScale Blog
MyScale Blog
博客园 - 三生石上(FineUI控件)
Hugging Face - Blog
Hugging Face - Blog
Microsoft Azure Blog
Microsoft Azure Blog
N
Netflix TechBlog - Medium
G
Google Developers Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻

kshao-blog-前端知识记录

win or mac clash 无 TUN 让 Antigravity、Chrome 强制 proxy(解决 Antigravity 无法加载选择 model、自动更新无法登录、跳转) 【大杂烩】在 pnpm 中直接修改 node_modules(.pnpm) 中的依赖项,项目中持久化 - pnpm 中的依赖处理、幽灵依赖、寻址规则等 在 html 中直接使用 Esm、Jsx 脚本快速调试和使用 React@19 和 Vue@3 源码,解决 React19 UMD 构建等问题 一键在本地批量检测并升级更新 package.json 中的模块依赖,ncu(npm-check-updates)在 npm、pnpm 或 workspace 项目中的使用教程 解决 Mac Docker Desktop 中启动出现的问题合集 通过阿里云、腾讯云无服务器搭建自定义的企业域名邮箱,实现在 QQ邮箱 收发等功能(附腾讯 SMTP 和 IMAP) 解决使用代理(clash 等)进行 SSH 连接(如 Github ssh key clone/push)出现 kex_exchange_identification 错误 静态文件资源 cdnjs, jsdelivr 抖音字节国内快速 CDN 镜像推荐【2025】- 仍在使用 bootcdn 和 staticfile CDN 请注意验证资源的完整性(SRI) pnpm monorepo 中管理依赖的最佳实践,与 Catalogs(目录)协议的使用(monorepo 中统一版本管理) Web 安全中的 Secure Contexts(安全上下文)- 解决在本地中使用 clipboard 或 Crypto 等 API 限制或关闭上下文限制 使用 serve 配合 openssl 或 mkcert 创建本地自签名可信任的证书 - 创建本地 TLS\SSL https 协议服务 利用 Github Actions 和 Acme 自动申请、更新和部署至阿里云、腾讯云 CDN Lets Encrypt SSl\TLS ECC RSA 双证书 【CSS】解决在 flex 容器中使用 align-content 或 justify-content 属性 center 居中时的溢出滚动和截断问题 - 理解 safe 关键字 在线工具 - 一键获取下载抖音无水印视频、抖音去水印解析工具、下载抖音无水印高清图集【2025 最新】 【React Router】v6 data router 在非组件(或工具方法)中如何优雅的跳转路由 【React】为什么路由跳转时页面滚动高度不会被重置(保留上个页面高度)?理解 history scrollRestoration 的场景与使用,以及如何使用 React Router 重置和跳转前保留滚动高度 【React】在本地 Html 中快速 debug(调试)React 源码 【React】结合源码和 EventLoop 分析 - 为什么 useLayoutEffect 会阻止 DOM 重绘(而 useEffect 闪烁)?为什么其内部 useState 会“同步”执行? React Compiler - 解放在函数中编程时的性能焦虑(React Conf 2024)附 Next 在线演示 在 github actions 中获取时间,并转换为中国标准时间(中国时区) 【npm】npm ci - npm clean install,在 CI、CD 中保持构建的一致性和可重复性 eslint 9.x 升级或使用指南,eslint.config.js 配置,包含 react、typescript、prettier 等常用配置升级迁移 使用 Spicetify 自定义 Spotify - 歌词翻译、全屏展示、主题替换 在 node 中快速代理请求(Proxy),解决跨域或请求转发问题 - http-proxy-middleware 修改请求体和返回 在 Hexo 中使用 AI(Gemini、deepseek、Azure)生成文章摘要,支持自定义模板。hexo-ai-summaries 插件文档(默认适配主题 Butterfly) 解决在 webstorm 或 idea 等 jetbrains 工具中遇到 Git 无法 force push,或 force push 灰色禁用无法点击(protected branches) hexo-seo-submit,Hexo 博客 SEO 优化插件 - 每日定时自动或手动提交链接至百度、Bing、Google,支持 Github Actions 和 Coding Jenkins 等CI(Hexo 插件编写) 一文吃透 pnpm 如何使用 workspace 构建 monorepo,与 npm、yarn 的用法对比(pnpm 9.x 内部安装依赖问题 link-workspace-packages) 【Node】Corepack - 解决 pnpm 或 yarn 的多版本管理、解决本地版本与 packageManager 中的版本一致性问题 解决 npm、cnpm 或 pnpm install 遇到 certificate has expired (证书已过期)
【web-worker】浅析 useWorker 库如何只需函数方法即可在 wor...
kshao · 2022-10-12 · via kshao-blog-前端知识记录

最近在看 useWorker 库的时候发现该 hook 只需传入函数即可运行,虽然说 worker 不经常使用,但是就酱紫直接用不需要一个 js 文件承接?

来看看 MDN 中如何创建一个 Worker

var myWorker = new Worker('worker.js');

再看看 useWorker 如何使用

useWorker Usage

import React from 'react';
import { useWorker } from '@koale/useworker';

const numbers = [...Array(5000000)].map((e) => ~~(Math.random() * 1000000));
const sortNumbers = (nums) => nums.sort();

const Example = () => {
  const [sortWorker] = useWorker(sortNumbers);

  const runSort = async () => {
    const result = await sortWorker(numbers); // non-blocking UI
    console.log(result);
  };

  return (
    <button type="button" onClick={runSort}>
      Run Sort
    </button>
  );
};

源码解析与最简实现

Demo

请打开控制台查看差异与结果~

最简实现

提取了下 useWorker 的大致逻辑,简化实现了下~主要看下核心逻辑,”凭空”创建 worker

// create worker
const createWWorker = (fn) => {
  console.log('worker run');
  let promise = {};
  const jobRunner = (options) => (e) => {
    const [userFuncArgs] = e.data;
    return Promise.resolve(options.fn(...userFuncArgs))
      .then((result) => {
        postMessage(['SUCCESS', result]);
      })
      .catch((error) => {
        postMessage(['ERROR', error]);
      });
  };

  const blobCode = `
    onmessage=(${jobRunner})({
      fn: (${fn}),
    })
  `;

  const blob = new Blob([blobCode], { type: 'text/javascript' });

  const jsUrl = URL.createObjectURL(blob);

  const worker = new Worker(jsUrl);

  worker.addEventListener('message', (e) => {
    const [status, result] = e.data;

    switch (status) {
      case 'SUCCESS': {
        promise.resolve(result);
        break;
      }
      default:
        promise.reject(result);
        break;
    }

    if (jsUrl) {
      worker.terminate();
      URL.revokeObjectURL(jsUrl);
      promise = {};
    }
  });

  const runWorker = (...restArgs) =>
    new Promise((resolve, reject) => {
      promise.resolve = resolve;
      promise.reject = reject;
      worker.postMessage([restArgs]);
    });

  return runWorker;
};

// usage
const worker = createWWorker(bubbleSort);
const result = await worker(bigNumbers);

看看如何通过代码生成 url 传给 worker

const blobCode = `
    onmessage=(${jobRunner})({
      fn: (${fn}),
    })
  `;

const blob = new Blob([blobCode], { type: 'text/javascript' });

const jsUrl = URL.createObjectURL(blob);

const worker = new Worker(jsUrl);

第一段看起来可能比较疑惑,函数 toString 后放入到 script 里也可以运行?试试就逝世~复制下面代码到控制台。

好吧,script type=”text/javascript“ 忘记这个了,函数 toString 后,比如闭包啊 this 指向等,可能都会有点问题,建议为纯函数~

const script = document.createElement('script');
const script = document.createElement('script');
script.innerText = `const test = 333; document.addEventListener('click', () => {
  console.log(test);
  })`;
document.body.appendChild(script);

通过生成 Blob 创建资源 Url

第一段生成 Blob 流,再通过流来创建 URL 当作 worker 的文件,思路清晰我是菜 B ~还得学~

const blob = new Blob([blobCode], { type: 'text/javascript' });

const jsUrl = URL.createObjectURL(blob);

可能接触不多,往往会弄混或遗忘这些方法~简单描述下~

Web Socket

WebSocket是基于 TCP 的一个全双工通信协议,HTML5 的新特性。
在此之前,客户端和服务端通信的时候,在客户端发送请求之后,服务端才能有所应答。如果服务器有新数据的话不能主动发至客户端,只能客户端进行:

  • 轮询:客户端不断发送新请求给服务端,服务端在应答一次后就断开连接,需不断发起新请求和新连接,造成资源的浪费。
  • 长轮询:客户端发送请求后,不关闭连接,等服务端有期望数据返回后关闭连接。弊端在于服务端需要保持连接,造成资源浪费
    WebSocket 的好处就是在于服务器可以主动发送资源到客户端,且只需一次连接,减少资源损耗。连接后,服务端可以不断的发送数据给客户端,之间无需再连接。

Web Worker

由于 JavaScript 为单线程,在计算一些密集型或高延性的任务时,会影响到整个页面的运行,WebWorker 应声而出。

Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。在主线程运行的同时,Worker 线程在后台运行,两者互不干扰。等到 Worker 线程完成计算任务,再把结果返回给主线程。这样的好处是,一些计算密集型或高延迟的任务,被 Worker 线程负担了,主线程(通常负责 UI 交互)就会很流畅,不会被阻塞或拖慢。
Worker 线程一旦新建成功,就会始终运行,不会被主线程上的活动(比如用户点击按钮、提交表单)打断。这样有利于随时响应主线程的通信。但是,这也造成了 Worker 比较耗费资源,不应该过度使用,而且一旦使用完毕,就应该关闭。
引用自阮一峰老师的文章《Web Worker 使用教程》

Service Worker

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

  • 安装(Installing)
    在浏览器加载了运用 Service Worker 的页面时,Service Worker 的 JS 文件也会被保存下来,然后运行安装,下载相应缓存。安装完成后,就会激活 Service Worker(Activated)
  • 激活(Activated)
    激活 Service Worker 后,Service Worker开始控制页面后台,当您刷新页面或者发送请求的时候,Service Worker 会对请求进行拦截,然后进行相应的操作(一般是看是否命中缓存,如果命中,就直接返回缓存,不需要再发送请求)

Service Worker在浏览器运行的时候,每隔一段时间,它会在后台尝试重新下载Service Worker的JS文件,只要新的JS文件和旧的有一点不相同,那么就会重新安装-激活。BTW,Service Worker也是Web Work的一种。