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('需高亮的代码文本');
相关推荐
女生寝室0387 分钟前
DiskSGenius Pro [6.0.1.1645][单文件汉化版] 下载
前端
前端老宋Running17 分钟前
别让你那 5MB 的 JS 文件把用户吓跑:React 代码分割(Code Splitting)实战指南
前端·javascript·react.js
小飞侠在吗41 分钟前
vue ref
前端·javascript·vue.js
悟能不能悟42 分钟前
在 Vue Router 4 中,如何设置base参数
前端·javascript·vue.js
Lovely_Ruby1 小时前
前端er Go-Frame 的学习笔记:实现 to-do 功能(三),用 docker 封装成镜像,并且同时启动前后端数据库服务
前端·后端
kong@react1 小时前
react+ts项目,富文本开发(wangEditor)
前端·react.js·前端框架
重铸码农荣光1 小时前
AI First + Mobile First:用大模型重构下一代应用开发范式
前端·架构·llm
Lovely_Ruby1 小时前
前端er Go-Frame 的学习笔记:实现 to-do 功能(二),前端项目的开发,对接后端
前端
willingtolove2 小时前
使用chrome修改请求参数重新发送请求
前端·chrome
-曾牛2 小时前
CSRF跨站请求伪造:原理、利用与防御全解析
前端·网络·web安全·网络安全·渗透测试·csrf·原理解析