Worklet представляет собой специализированный механизм выполнения кода в отдельном, изолированном контексте с минимальным доступом к глобальному окружению браузера. В отличие от традиционных Web Workers, worklet-ы ориентированы на выполнение высокопроизводительных, коротких и частых операций, таких как рендеринг графики, обработка аудио или вычисления, связанные с анимациями.
Ключевая особенность worklet-ов заключается в их интеграции в критические пути браузера: рендеринг, аудио-граф и анимационные циклы. Это делает их крайне чувствительными к производительности и архитектуре кода.
Worklet выполняется в отдельной среде, но с более ограниченным API по сравнению с Web Worker:
windowКод worklet-ов загружается через метод addModule(),
который принимает путь к JavaScript-файлу и выполняет его в
специализированном контексте.
CSS.paintWorklet.addModule('/paint-worklet.js');
Архитектурно worklet-ы ориентированы на многократное выполнение небольших функций, а не на длительные фоновые задачи.
CSS Houdini представляет собой набор низкоуровневых API, позволяющих разработчикам напрямую вмешиваться в процесс рендеринга CSS. Worklet-ы являются центральным механизмом этой технологии.
Paint Worklet позволяет создавать пользовательские CSS-изображения, генерируемые программно во время рендеринга.
Регистрация paint-worklet:
registerPaint('diagonalLines', class {
paint(ctx, geom, properties) {
const step = 10;
for (let i = 0; i < geom.width; i += step) {
ctx.beginPath();
ctx.moveTo(i, 0);
ctx.lineTo(i - geom.height, geom.height);
ctx.stroke();
}
}
});
Использование в CSS:
.box {
background-image: paint(diagonalLines);
}
Особенности Paint Worklet:
Layout Worklet позволяет полностью переопределять алгоритмы раскладки элементов.
Пример регистрации:
registerLayout('simpleGrid', class {
async intrinsicSizes() {}
async layout(children, edges, constraints, styleMap) {
let inlineOffset = 0;
let blockOffset = 0;
const childFragments = [];
for (const child of children) {
const childFragment = await child.layoutNextFragment();
childFragment.inlineOffset = inlineOffset;
childFragment.blockOffset = blockOffset;
inlineOffset += childFragment.inlineSize;
childFragments.push(childFragment);
}
return {
childFragments
};
}
});
Особенности Layout Worklet:
Animation Worklet используется для создания высокопроизводительных анимаций, работающих вне основного thread’а.
Пример:
registerAnimator('parallaxScroll', class {
constructor(options) {
this.speed = options.speed || 1;
}
animate(currentTime, effect) {
const offset = currentTime * this.speed;
effect.localTime = offset;
}
});
Использование:
const effect = new KeyframeEffect(
element,
[{ transform: 'translateY(0px)' }, { transform: 'translateY(100px)' }],
{ duration: 1000, fill: 'both' }
);
new WorkletAnimation('parallaxScroll', effect, document.timeline, { speed: 0.5 }).play();
Audio Worklet предназначен для обработки аудиопотока в реальном
времени с минимальной задержкой. Он является заменой устаревшего
ScriptProcessorNode.
Главное требование — детерминированная и быстрая обработка аудиобуфера.
class GainProcessor extends AudioWorkletProcessor {
process(inputs, outputs, parameters) {
const input = inputs[0];
const output = outputs[0];
const gain = parameters.gain ? parameters.gain[0] : 1;
for (let channel = 0; channel < input.length; channel++) {
const inputChannel = input[channel];
const outputChannel = output[channel];
for (let i = 0; i < inputChannel.length; i++) {
outputChannel[i] = inputChannel[i] * gain;
}
}
return true;
}
}
registerProcessor('gain-processor', GainProcessor);
const audioContext = new AudioContext();
await audioContext.audioWorklet.addModule('/gain-processor.js');
const node = new AudioWorkletNode(audioContext, 'gain-processor', {
parameterData: { gain: 0.5 }
});
const source = audioContext.createMediaElementSource(audioElement);
source.connect(node).connect(audioContext.destination);
Архитектура worklet накладывает жёсткие ограничения:
fetch в синхронном
режимеЭти ограничения обусловлены необходимостью сохранения стабильного FPS и минимальной задержки в критических подсистемах браузера.
При использовании сборщика Parcel worklet-файлы рассматриваются как
отдельные entry-point модули. Это связано с тем, что worklet-скрипты
загружаются через addModule() и должны существовать как
самостоятельные JavaScript-ресурсы.
src/
index.js
paint-worklet.js
audio/
gain-processor.js
import paintWorkletUrl from './paint-worklet.js?url';
CSS.paintWorklet.addModule(paintWorkletUrl);
Parcel обрабатывает ?url как запрос на генерацию
отдельного файла и возвращает путь к собранному артефакту.
Parcel автоматически выносит worklet-ы в отдельные чанки при корректной конфигурации входных точек. Это важно для:
AudioWorklet модули также должны быть доступны по URL:
import audioWorkletUrl from './audio/gain-processor.js?url';
await audioContext.audioWorklet.addModule(audioWorkletUrl);
Parcel обеспечивает:
Эффективное применение worklet-архитектуры требует учёта ряда факторов:
process и
paintОсобенно критично это для Audio Worklet, где даже небольшие задержки приводят к слышимым артефактам.
| Характеристика | Worklet | Web Worker |
|---|---|---|
| Доступ к DOM | отсутствует | отсутствует |
| Производительность | выше в спец. задачах | универсальная |
| Задержка | минимальная | средняя |
| Использование | рендер/аудио/анимации | фоновые задачи |
| Гибкость | ограниченная | высокая |
Worklet-ы не заменяют Web Workers, а дополняют их в узкоспециализированных сценариях.
Worklet-ы формируют слой низкоуровневой оптимизации, позволяющий переносить критические вычисления ближе к внутренним конвейерам браузера. Их использование оправдано в случаях, где:
В таких сценариях worklet-ы становятся частью архитектуры производительного frontend-слоя, интегрируясь с системой сборки и модульности JavaScript-приложений.