Offscreen Canvas — ускорьте свой Canvas с помощью Web Workers

JavaScript

Теперь вам не нужно рисовать изображения в основном потоке благодаря Offscreen Canvas!

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

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

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

К счастью,OffscreenCanvasВы можете решить эту проблему на экране Hanvas!

До сих пор функции холста и рисования<canvas>Теги связаны вместе, что означает, что Canvas API и DOM связаны. OffscreenCanvas, как следует из названия, разделяет DOM и Canvas API, перемещая Canvas за пределы экрана.

Из-за этого разъединения рендеринг OffscreenCanvas полностью отделен от DOM, и он немного быстрее, чем обычный Canvas, просто потому, что между ними (Canvas и DOM) нет синхронизации. Но что более важно, после их разделения Canvas можно будет использовать в Web Worker, даже если в Web Worker нет DOM. Это открывает больше возможностей для Canvas.

Использование OffscreenCanvas в Worker

Workers— это веб-версия потоков — она позволяет запускать ваш код за кулисами. Размещение части вашего кода в Worker может дать вашему основному потоку больше времени простоя, что улучшит ваш пользовательский опыт. Точно так же, как у него нет DOM, до сих пор в Worker не было Canvas API.

OffscreenCanvas не зависит от DOM, поэтому Canvas API можно заменить каким-либо методом в Worker. Вот как я использую 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[]);
}

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 [передается](developer.Mozilla.org/en-US/docs/…). Помимо указания его как одного из полей в переданном сообщении, его также необходимо передать вторым параметром в postMessage (метод, который передает сообщение в Worker), чтобы его можно было использовать в контексте Worker нить .

В 🌰 ниже при изменении цветовой темы происходит «сложный расчет», и этот расчет занимает несколько миллисекунд даже на высокопроизводительном рабочем столе. И вы можете запустить эту анимацию в основном потоке или в рабочем потоке. В основном потоке вы не сможете взаимодействовать с кнопкой, пока запускаются сложные вычисления — поток заблокирован. Под Worker не влияет на реакцию UI.

Demo

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

Demo

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

Использование с популярными библиотеками

Поскольку API 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 требует, чтобы Canvas имел свойства style.width и style.height. OffscreenCanvas полностью отделен от DOM и не имеет этих свойств. Поэтому вам нужно предоставить эти свойства самостоятельно, либо удалив их из логики three.js, либо написав собственную логику, связывающую эти значения с начальными измерениями Canvas.

Вот демонстрация базовой анимации Three.js:

Demo

Но помните, что есть некоторые, связанные с API DOM. Некоторые идеи в этом отношении начали пытаться проверитьВидео с Google I/O 2017.

Метод commit(), показанный в примерах в этом видео, не рекомендуется. Вместо этого используйте worker.requestAnimationFrame.

В заключение

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

OffscreenCanvas можно использовать в Chrome 69 без включения флага (экспериментальная функция). Он также реализуется Firefox. Поскольку его API очень похож на обычный элемент холста, вы можете легко добавить его и использовать шаг за шагом, не нарушая логику работы вашего существующего приложения или библиотеки. OffscreenCanvas имеет преимущества в производительности в любой ситуации, связанной с графическими вычислениями и производительностью анимации, и не имеет тесной связи с DOM (то есть не сильно зависит от DOM API).

Другие источники