Web Worker 前端性能提升

在Web开发中,有时我们的应用需要处理复杂的计算或大量数据的操作,由于JavaScript语言采用的是单线程,如果有多个同步计算任务执行,则在这段同步计算逻辑执行完之前,它下方的代码不会执行,从而造成了阻塞,用户的交互也可能无响应。

如果把大量耗时的计算放到 Web Worker 执行,在这段逻辑计算运行期间不影响执行下面的任务,用户的操作也可以响应,就不会出现页面卡顿的现象了。

Web Worker 的基本应用

javascript 复制代码
// 创建一个 Worker 实例 
const myWorker = new Worker("worker.js");

// 向 Worker 发送数据 
myWorker.postMessage('Message posted to worker'); 

// 监听 Worker 返回的数据
myWorker.onmessage = function(event) { 
    console.log('Received message from worker: ' + event.data); 
};

在 worker 中接收到消息后,我们可以写这样一个事件处理函数代码作为响应(worker.js)

worker.js 复制代码
onmessage = (e) => {
  console.log("Message received from main script");
  const workerResult = `Result: ${e.data}`;
  console.log("Posting message back to main script");
  postMessage(workerResult);
};

Web Worker 编译

这里以 webpack 为例。

方式一:web worker 独立编译

webpack.config.js 配置目标(target)指定环境为 webworker,编译成一个 web worker。

webpack.config.js 复制代码
module.exports = {
  // ...
  target: 'webworker',
};

方式二:原生 Worker 支持

当把资源的 new URL 和 new Worker 结合起来时,webpack 会自动为 web worker 创建一个新的入口点(entrypoint)。

javascript 复制代码
new Worker(new URL("./worker.js", import.meta.url))

代码高亮实例

下面是一个利用 remark-shaku-code-annotate 实现代码高亮的示例。

创建代码高亮 web worker

安装包

css 复制代码
npm i @stefanprobst/remark-shiki remark remark-html remark-shaku-code-annotate shiki

创建 worker.js

worker.js 复制代码
import { remark } from 'remark';
import { remarkShakuCodeAnnotate } from 'remark-shaku-code-annotate';

const processor = remark().use(remarkShakuCodeAnnotate, {
    theme: 'github-light',
    langs: ['javascript', 'css', 'jsx', 'html', 'typescript', 'tsx'],
    paths: {
        themes: './static/shiki/themes',
        wasm: './static/shiki/dist',
        languages: './static/shiki/languages',
    },
});

onmessage = (e) => {
    // 接收需要高亮的代码文本
    const code = e.data;
    
    // 将代码文本高亮
    processor.process(code).then((data) => {
        // 将高亮后的代码文本(html)发送给主程序
        postMessage(data.toString());
    });
};

使用 webpack 编译

webpack.config.js 复制代码
module.exports = function (env, args = {}) {
    const config = {
        // ...
        // 编译成 web worker
        target: 'webworker',
        plugins: [
            // ...
            // 将需要用到的 shiki 下的资源文件拷贝至编译输出目录
            new CopyWebpackPlugin({
                patterns: [
                    {
                        from: 'shiki/dist/*',
                        context: path.resolve(__dirname, 'node_modules'),
                        to: 'static/',
                    },
                    {
                        from: 'shiki/languages/*',
                        context: path.resolve(__dirname, 'node_modules'),
                        to: 'static/',
                    },
                    {
                        from: 'shiki/themes/*',
                        context: path.resolve(__dirname, 'node_modules'),
                        to: 'static/',
                    },
                ],
            }),
        ],
    };

    return config;
};

创建 worker 实例

在主程序中将编译的 web worker 拷贝至根目录的 remark-shaku-web-worker 下。

配置 webpack.config.js

webpack.config.js 复制代码
module.exports = function (env, args = {}) {
    const config = {
        // ...
        plugins: [
            // ...
            // 将需要用到的 shiki 下的资源文件拷贝至编译输出目录
            new CopyWebpackPlugin({
                patterns: [
                    {
                        from: '**/*',
                        context: path.resolve(__dirname, 'packages/remark-shaku-web-worker/dist'),
                        to: 'remark-shaku-web-worker/',
                    },
                ],
            }),
        ],
    };

    return config;
};

在主程序中创建 worker 实例,将代码文本转换成高亮 html

javascript 复制代码
const myWorker = new Worker('/remark-shaku-web-worker/worker.js');
myWorker.onmessage = (e) => {
    // 高亮后的代码文本(html)
    const textContent = e.data;
};
myWorker.postMessage('需高亮的代码文本');
相关推荐
有味道的男人11 分钟前
搜好货平台关键词商品搜索接口:分页容错与商品数据轻量化提取方案
服务器·前端·javascript
lovingsoft1 小时前
Chrome Lighthouse 详解
前端·chrome
Qlly1 小时前
全栈工程师怎么接需求?从一句「加个功能」聊到能开发、能验收
前端·后端
马可家的菠萝1 小时前
你的微信“文件传输助手”,是不是已经成了第二个网盘?
前端·后端·架构
略略略啦1 小时前
Vibe Coding 基于Spec DD和TDD的实践指南
前端
shmily麻瓜小菜鸡1 小时前
前端实现图片与PDF文字识别敏感信息打码方案
前端·pdf·状态模式
打工仔折腾 AI2 小时前
LangChain 工具调用实战:从 Tool 定义到 Agent 执行链路拆解
java·前端·人工智能·后端·python·langchain·ai agent 实战
汉堡大王95272 小时前
单次输出拉到100万Token:拆完 Gemini 4 Argon 的续写协议,才看懂谷歌这7个月在憋什么
前端·人工智能·后端
看浪的路人2 小时前
第9讲:大模型应用监控与可观测性——OpenTelemetry + Prometheus + Grafana 全链路追踪
java·前端·spring
内存过载2 小时前
用表格模拟甘特图:项目排期的土办法
前端·低代码