【Canvas 系列】通过 OffscreenCanvas + Worker 提高书写性能

前言

上一节我们通过【Canvas系列】通过离屏渲染提高 Canvas 书写性能,但是在绘制的过程中,我们会发现,当绘制的图形越来越多时,Canvas 的渲染性能会越来越差,这是因为我们在绘制图形会阻塞主线程,如果主线程中还有其他的任务也会表现出卡顿的效果,Canvas 的渲染性能越来越差。

这节我们将通过 OffscreenCanvas + Worker 将绘制图形的任务放到 Worker 中进行,避免阻塞主线程,从而提高 Canvas 的渲染性能。

实现思路

在 worker 线程中是无法操作 DOM 的,但 OffscreenCanvas 可以在 worker 线程中进行操作,因此我们可以通过 OffscreenCanvas 将绘制图形的任务放到 worker 线程中进行。这样可以减少主线程的任务,从而提高书写性能。

具体实现

创建 OffscreenCanvas

js 复制代码
const canvas = document.getElementById('draw');
const offScreenCanvas = canvas.transferControlToOffscreen(); // 将 canvas 转换为 offScreenCanvas

将 offScreenCanvas 传递给 worker 线程

js 复制代码
const worker = new Worker('./worker.js'); // 创建一个 webWorker
const offScreenCanvas = canvas.transferControlToOffscreen(); // 将 canvas 转换为 offScreenCanvas

worker.postMessage({
    type: 'init',
    offScreenCanvas,
    width: width,
    height: height,
    dpr,
}, [offScreenCanvas]); // 将 offScreenCanvas 传递给 webWorker


worker.onmessage = function (e) {
    const type = e.data.type;
    switch (type) {
        case 'init':
            init = true; // 判断是否初始化完毕
            break;
    }
}

通过监听事件获取书写的坐标点传递给 worker 线程, 然后在 worker 线程中进行绘制

js 复制代码
/**
 * 自由画笔的实现思路
 * 1 监听鼠标事件
 * 2 将鼠标移动的轨迹记录下来
 * 3 然后将这些点连接成线
 */
canvas.addEventListener("pointerdown", (e) => {
    if (!init) return;
    start = true; // 通过监听鼠标按下事件,来判断是否开始绘制
    addPoint(e); // 将鼠标按下的点添加到points数组中
});

canvas.addEventListener(
    "pointermove",
    (e) => {
        console.log("e--->throttle", e);
        if (!start) return; // 如果没有按下,则不绘制
        addPoint(e); // 将鼠标移动的点添加到points数组中
        init && worker.postMessage({
            type: 'render',
            points,
        }); // 将 点 传递给 webWorker
    }
);

canvas.addEventListener("pointerup", (e) => {
    start = false;
    points = []; // 绘制完毕后,清空points数组
});


/*
* 将鼠标事件的点转化为相对于canvas的坐标上的点
*/
function addPoint(e) {
    const x = e.clientX;
    const y = e.clientY;
    points.push({
        x,
        y,
    });
}

实现效果

具体代码

参考文章

相关推荐
To_OC2 小时前
从一头雾水到跑通全流程:我用一个周末啃透了JWT登录鉴权
前端·后端·http
excel4 小时前
研究 Vue 3 源码的收获
前端·vue.js
可乐鸡翅yeah_6 小时前
业务中 M3U8 水印相关坑,硬水印和动态水印区别
前端·网络·数据库·ffmpeg·m3u8在线
lerhxx6 小时前
AI 应用如何高效优雅地恢复中断?—— "连接解耦 + 状态持久化"
前端·javascript
计算机魔术师6 小时前
METR 演示 AI 智能体如何篡改 Inspect 评估记录以掩盖不当行为
前端
前端snow7 小时前
ai agent --- 异步处理之 Rabbit MQ
前端
念何架构之路7 小时前
zap扩展生态与总结
java·前端·数据库
独孤九剑打醒他7 小时前
【原创开源】【概念设计】源 - 栅 - 漏 - 栅 - 源 横向双栅 MOS,低压交流多值逻辑芯片探索
前端·其他·架构·开源·硬件工程
mantou1327 小时前
我给 AI Agent 做了个「油猴」:让 Claude Code / Codex 直接用你已登录的浏览器
前端·javascript·后端
默_笙7 小时前
🍕 一个主编、三个工种、两本手册:搭一支 AI 调研队
前端·javascript