OffscreenCanvas — ускорьте работу с холстом с помощью веб-воркера.

Tim Dresser

Canvas — популярный способ рисования всевозможной графики на экране и точка входа в мир WebGL. Его можно использовать для рисования фигур, изображений, запуска анимации или даже отображения и обработки видеоконтента. Его часто используют для создания красивого пользовательского опыта в мультимедийных веб-приложениях и онлайн-играх.

Он доступен для сценариев, что означает, что контент, нарисованный на холсте, может быть создан программно, например, на JavaScript. Это дает холсту большую гибкость.

В то же время на современных веб-сайтах выполнение скриптов является одним из наиболее частых источников проблем с реагированием пользователей . Поскольку логика холста и рендеринг происходят в том же потоке, что и взаимодействие с пользователем, (иногда тяжелые) вычисления, связанные с анимацией, могут нанести ущерб реальной и воспринимаемой производительности приложения.

К счастью, OffscreenCanvas является ответом на эту угрозу.

Поддержка браузера

  • Хром: 69.
  • Край: 79.
  • Фаерфокс: 105.
  • Сафари: 16.4.

Источник

Раньше возможности рисования на холсте были привязаны к элементу <canvas> , а это означало, что он напрямую зависел от DOM. OffscreenCanvas, как следует из названия, отделяет DOM и Canvas API, перемещая его за пределы экрана.

Благодаря этому отделению рендеринг OffscreenCanvas полностью отделен от DOM и, следовательно, обеспечивает некоторое повышение скорости по сравнению с обычным холстом, поскольку между ними нет синхронизации.

Более того, его можно использовать в Web Worker даже при отсутствии доступного DOM. Это позволяет реализовать всевозможные интересные варианты использования.

Используйте OffscreenCanvas в рабочем

Воркеры — это веб-версия потоков, позволяющая запускать задачи в фоновом режиме.

Перемещение части ваших сценариев в рабочий процесс дает вашему приложению больше возможностей для выполнения критически важных для пользователя задач в основном потоке. Без OffscreenCanvas не было возможности использовать Canvas API в воркере, так как не было доступного DOM.

OffscreenCanvas не зависит от DOM, поэтому его можно использовать. В следующем примере OffscreenCanvas используется для расчета цвета градиента в рабочем потоке:

// 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 )

Разблокировать основной поток

Перенос тяжелых вычислений в рабочий процесс позволяет освободить значительные ресурсы в основном потоке. Используйте метод TransferControlToOffscreen для зеркального отражения обычного холста в экземпляре OffscreenCanvas. Операции, примененные к OffscreenCanvas, будут автоматически отображаться на исходном холсте.

const offscreen = document.querySelector('canvas').transferControlToOffscreen();
const worker = new Worker('myworkerurl.js');
worker
.postMessage({canvas: offscreen}, [offscreen]);

В следующем примере тяжелые вычисления происходят при изменении цветовой темы — это должно занять несколько миллисекунд даже на быстром рабочем столе. Вы можете запускать анимацию в основном потоке или в рабочем потоке. В случае с основным потоком вы не можете взаимодействовать с кнопкой во время выполнения тяжелой задачи — поток блокируется. В случае работника это не влияет на скорость реагирования пользовательского интерфейса.

Демо

Это работает и в обратную сторону: занятой основной поток не влияет на анимацию, выполняемую воркером. Вы можете использовать эту функцию, чтобы избежать визуальных зависаний и гарантировать плавную анимацию, несмотря на трафик основного потока, как показано в следующей демонстрации.

Демо

В случае обычного холста анимация останавливается, когда основной поток искусственно перегружается, в то время как OffscreenCanvas на основе воркера воспроизводится плавно.

Поскольку API OffscreenCanvas обычно совместим с обычным элементом 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, не имеет его, поэтому вам необходимо предоставить его самостоятельно, либо отключив его, либо предоставив логику, которая связывает эти значения с исходными размерами холста.

Ниже показано, как запустить базовую анимацию Three.js в воркере:

Демо

Имейте в виду, что некоторые API-интерфейсы, связанные с DOM, недоступны в воркере, поэтому, если вы хотите использовать более продвинутые функции Three.js, такие как текстуры, вам могут потребоваться дополнительные обходные пути. Некоторые идеи о том, как начать с ними экспериментировать, можно найти в видео с Google I/O 2017 .

Если вы активно используете графические возможности Canvas, OffscreenCanvas может положительно повлиять на производительность вашего приложения. Доступность контекстов рендеринга холста для работников увеличивает параллелизм в веб-приложениях и позволяет лучше использовать многоядерные системы.

Дополнительные ресурсы