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('需高亮的代码文本');
相关推荐
web1350858863510 分钟前
前端node.js
前端·node.js·vim
m0_5127446411 分钟前
极客大挑战2024-web-wp(详细)
android·前端
潜意识起点35 分钟前
精通 CSS 阴影效果:从基础到高级应用
前端·css
奋斗吧程序媛40 分钟前
删除VSCode上 origin/分支名,但GitLab上实际上不存在的分支
前端·vscode
IT女孩儿1 小时前
JavaScript--WebAPI查缺补漏(二)
开发语言·前端·javascript·html·ecmascript
m0_748256563 小时前
如何解决前端发送数据到后端为空的问题
前端
请叫我飞哥@3 小时前
HTML5适配手机
前端·html·html5
@解忧杂货铺5 小时前
前端vue如何实现数字框中通过鼠标滚轮上下滚动增减数字
前端·javascript·vue.js
F-2H7 小时前
C语言:指针4(常量指针和指针常量及动态内存分配)
java·linux·c语言·开发语言·前端·c++
gqkmiss7 小时前
Chrome 浏览器插件获取网页 iframe 中的 window 对象
前端·chrome·iframe·postmessage·chrome 插件