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 URLnew 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('需高亮的代码文本');
相关推荐
晴天161 小时前
浏览器中ESM与AMD模块共存的解决方案
前端·node.js
mONESY1 小时前
对话一长上下文就爆?LangChain.js Memory 三种淘汰策略(截断 / 总结 / 检索)实战
javascript
芳心粽伙饭1 小时前
CSS第一章 CSS引入
前端·css
雪芽蓝域zzs2 小时前
第三十二节:部门组织管理(el‑tree 组织树
前端·javascript·vue.js
leoZ2312 小时前
第 7 篇:进阶——校验、联动、列表页
开发语言·前端·javascript·vue.js·人工智能·目标检测·ecmascript
VeryCool2 小时前
别吹了,依赖图像识别的GPT‑6 Astra永远快不起来
前端·javascript·aigc
hunterandroid2 小时前
Android 测试全景:从单元测试到 UI 自动化的完整实践
android·前端
leoZ2312 小时前
第 8 篇:与 AI 协作的工作流 + 完整案例
前端·人工智能·神经网络·自然语言处理·性能优化·c#·php
背对疾风2 小时前
提前还贷,缩短年限和降低月供其实是一样的
前端
2501_928996222 小时前
Agent 开发 API 选型:硅碳相变下 Function Calling 兼容性与多模型路由拆解
前端