画布是一种很常用的工具 在屏幕上绘制各种图形,以及进入 WebGL 世界的入口点。 它可用于绘制形状、图片、运行动画,甚至显示和处理视频内容。 它通常用于在富媒体 Web 应用中打造出色的用户体验, 在线游戏。
它是可编写脚本的,这意味着在画布上绘制的内容可以通过编程方式创建, 例如在 JavaScript 中这赋予画布极大的灵活性。
同时,在现代网站中,脚本执行是最常见的 用户响应的来源。 由于画布逻辑和渲染与用户互动发生在同一线程上, 动画中涉及的(有时非常繁重的)计算可能会损害应用的真实性能 以及用户感知到的广告效果
幸运的是,OffscreenCanvas 是对这种威胁的回应
以前,画布绘制功能与 <canvas>
元素相关联,
这意味着它直接依赖于 DOM。顾名思义,OffscreenCanvas
通过将 DOM 和 Canvas API 移出屏幕来将 DOM 与 Canvas API 分离开来。
由于这种分离,OffscreenCanvas 的渲染与 DOM 完全分离, 因此与常规画布相比,它在速度方面有所提升, 。
更重要的是,它可以在 Web Worker 中使用,即使没有 DOM 可用。这支持各种有趣的用例。
在 worker 中使用 OffscreenCanvas
工作器 是 Web 的线程版本,可让您在后台运行任务。
将部分脚本移至工作器可为您的应用提供更多提升空间,以便执行用户关键型任务 在主线程上执行任务如果没有 OffscreenCanvas,就无法在 worker 中使用 Canvas API,因为 没有可用的 DOM
OffscreenCanvas 不依赖于 DOM,因此可使用。以下示例使用 OffscreenCanvas 计算 Worker 中的渐变颜色:
// file: worker.js
function getGradientColor(percent) {
const canvas = new OffscreenCanvas(100, 1);
const ctx = canvas.getContext('2d');
const gradient = ctx.createLinearGradient(0, 0, canvas.width, 0);
gradient.addColorStop(0, 'red');
gradient.addColorStop(1, 'blue');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, ctx.canvas.width, 1);
const imgd = ctx.getImageData(0, 0, ctx.canvas.width, 1);
const colors = imgd.data.slice(percent * 4, percent * 4 + 4);
return `rgba(${colors[0]}, ${colors[1]}, ${colors[2]}, ${colors[3]})`;
}
getGradientColor(40); // rgba(152, 0, 104, 255 )
解锁主线程
将繁重的计算工作移至 Worker, 占用大量内存资源使用 transferControlToOffscreen 方法将常规画布镜像到 OffscreenCanvas 实例。应用于以下对象的操作: OffscreenCanvas 将自动呈现在源画布上。
const offscreen = document.querySelector('canvas').transferControlToOffscreen();
const worker = new Worker('myworkerurl.js');
worker.postMessage({canvas: offscreen}, [offscreen]);
在以下示例中,色彩主题发生变化时会进行大量计算,因此 即使是在速度较快的桌面设备上也要耗费几毫秒的时间。您可以选择在主线程上运行动画 还是在 worker 中。对于主线程,当内存占用量较大时,您无法与按钮进行交互 任务正在运行,则表明线程处于阻塞状态。对于工作器来说,对 界面响应速度。
它的运行方式也相反:繁忙的主线程不会影响在 一个工作器。您可以使用此功能来避免视觉卡顿,并保证动画流畅 如以下演示所示。
对于常规画布,当主线程人为过度工作时,动画会停止, 而基于 worker 的 OffscreenCanvas 可以流畅播放。
与常用库搭配使用
由于 OffscreenCanvas API 通常与常规 Canvas 元素兼容,因此您可以 也可以将其与市场上一些领先的图形库结合使用。
例如,您可以对它进行功能检测,如果可用,还可以将其与 Three.js 结合使用,方法是指定 渲染程序构造函数中的画布选项:
const canvasEl = document.querySelector('canvas');
const canvas =
'OffscreenCanvas' in window
? canvasEl.transferControlToOffscreen()
: canvasEl;
canvas.style = {width: 0, height: 0};
const renderer = new THREE.WebGLRenderer({canvas: canvas});
但有一个问题,就是 Three.js 要求画布具有 style.width
和 style.height
属性。
OffscreenCanvas 与 DOM 完全分离,因此没有该类,因此您需要自行提供。
方法是将其打桩,或者提供将这些值与原始值关联起来的逻辑
画布尺寸。
下面展示了如何在 worker 中运行基本的 Three.js 动画:
请注意,某些与 DOM 相关的 API 在 Worker 中并不直接可用,因此, 想要使用更高级的 Three.js 功能(例如纹理),则可能需要更多解决方法。 如需了解如何开始尝试这些功能,请参阅 2017 年 Google I/O 大会的视频。
如果您大量使用画布的图形功能,则 OffscreenCanvas 对 从而影响应用的性能向 worker 提供画布渲染上下文会增加 并行处理,并更好地利用多核系统。