Skip to content

Worker и производительность ​

О чём эта страница ​

При включённом workerMode алгоритмы дерева выполняются в Web Worker: главный поток только рендерит, а структурные изменения, поиск и выбор отправляются в Worker командами, и результаты возвращаются как «снимки видимых строк». Это подходит для двух ситуаций:

  • очень большой ввод, где первое построение заняло бы главный поток;
  • частые структурные изменения, где повторные правки постоянно запускают пересчёт MPTT.

Плата — один дополнительный round-trip postMessage на взаимодействие. На небольших данных режим главного потока на самом деле быстрее — поэтому workerMode по умолчанию выключен.

Параметры ​

propТипПо умолчаниюОписание
workerModebooleanfalseВыполнять алгоритмы дерева в Web Worker
chunkedBuildbooleanfalseПакетная запись узлов в WASM; действует только при outputIdOnly = true и без filterFn
buildBatchSizenumber2000Узлов в пакете (когда chunkedBuild включён)

Метрики ​

getBuildMetrics() ​

Возвращает длительности фаз последнего построения (в миллисекундах): inputBridgeMs, inputYieldMs, finalizeMs, layoutBridgeMs, cacheAssemblyMs, cacheYieldMs, layoutReleaseMs, cacheIndexMs, cacheRefreshMs, shownIndicesMs, selectionStatesMs, totalMs.

Когда нужно понять «почему первый кадр медленный», сначала смотрите totalMs, затем идите по списку выше и ищите, какая это фаза.

getWorkerMetrics() ​

ПолеСмысл
enabledДействительно ли используется Worker
pendingCommands / commandsSent / snapshotsReceivedГлубина очереди и накопительные счётчики
lastRoundTripMsRound-trip, как его видит главный поток
lastWorkerResponseMsВремя внутри Worker
lastWorkerSerializeMsВремя сериализации видимых строк
structuralBatches / structuralOperations / lastBatchSizeКак объединялись подряд идущие структурные операции

Объединение команд: подряд идущие структурные изменения не отправляются по одному — они объединяются в пакет в коротком окне кадра, поэтому structuralOperations обычно больше structuralBatches. Именно эту проблему оно и решает.

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

vue
<VueGiantTree :tree="rows" root="root" worker-mode v-model="selected" />
ts
const metrics = treeRef.value?.getWorkerMetrics()
if (metrics?.enabled) {
  console.log('round trip', metrics.lastRoundTripMs, 'мс', 'пакетов', metrics.structuralBatches)
}

Бенчмарки (release WASM, локальный Chromium) — в архиве performance-gate.

На что обратить внимание ​

Всё ниже измерено; без учёта этих пунктов легко получить «локально быстро, в продакшене медленно».

Для больших массивов используйте shallowRef ​

Компонент обходит и сериализует весь tree. Если хост держит его в глубоко реактивном ref, каждое чтение свойства проходит через get trap прокси, который лениво создаёт прокси для каждого вложенного объекта — замер на 100 000 узлов:

ВариантJSON.stringify(100 000 объектов)
обычный массив17.1ms
ref(...).value277.2ms
shallowRef(...).value19.6ms

Внутри компонента вызывается toRaw(), поэтому работают оба варианта, но shallowRef дешевле — данные дерева всегда заменяются целиком.

ts
// Рекомендуется
const rows = shallowRef(buildRows())
// Не рекомендуется
const rows = ref(buildRows())

Размер данных определяет, нужен ли Worker ​

Замерено на release WASM и локальном Chromium:

ДанныеworkerMode: falseworkerMode: true
10 000total 22.8ms, без блокировкиroundTrip 42.7ms, без блокировки
100 000total 242ms, главный поток заблокирован 249msroundTrip 53.4ms, без блокировки
1 000 000total 2697ms, главный поток заблокирован 2749msroundTrip 584ms

До 10 000 узлов основной поток быстрее (на один round-trip меньше); от ~100 000 предпочитайте Worker. Первое включение загружает скрипт воркера и WASM один раз, дальше они переиспользуются.

Меняйте данные через tree, а не через ремаунт с :key ​

vue
<!-- Рекомендуется: Worker и экземпляр WASM переиспользуются; ~600ms на 1 млн узлов -->
<VueGiantTree :tree="rows" worker-mode />

<!-- Не рекомендуется: каждая пересборка уничтожает и создаёт Worker заново -->
<VueGiantTree :key="reloadKey" :tree="rows" worker-mode />

Замена tree идёт по бинарному потоковому каналу (UTF-8 + transfer), а ремаунт каждый раз заново инициализирует Worker.

outputIdOnly / filterFn отключают chunkedBuild ​

chunkedBuild действует только при outputIdOnly === true и без filterFn. Иначе компонент возвращается к JSON-пути для всего дерева, и главный поток занимается целиком. inputBridgeMs === 0 в getBuildMetrics() означает, что пакетный путь не использовался.

Попробуйте ​

И переключатель workerMode, и оба метода метрик есть на полной демо-площадке: включите «workerMode», затем нажмите «getBuildMetrics / getWorkerMetrics» — панель покажет enabled=true и реальное время round-trip.