Skip to content

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

Движок рассчитан на сотни блоков и соединений и на блоки, которые приходят и уходят, — свёрнутые узлы деревьев, строки виртуализированных списков.

Что он делает за вас ​

  • Перерисовывается только изменившееся. Проход измеряет блоки, а затем переписывает те линии, у которых действительно изменились геометрия или вид. Пути и DOM-узлы остальных используются повторно. Перетаскивание блока с 20 линиями среди 300 затрагивает эти 20.
  • Чтение и запись разделены. Каждый прямоугольник измеряется один раз за кадр, до любой записи в DOM; размеры подписей кэшируются. Принудительных пересчётов раскладки посреди прохода нет.
  • Блок без соединений ничего не стоит. Он не наблюдается через ResizeObserver и не измеряется. Его регистрируют, когда появляется первое соединение (или когда он может начать или закончить его в режиме создания связей).
  • Вывод не меняется. При настройках по умолчанию SVG байт-в-байт такой же, как рисовал 0.4.3.

Пакетное обновление ​

batch(fn) выполняет fn и затем рисует один раз, сколько бы блоков, соединений или изменений конфигурации там ни было:

ts
linker.batch(() => {
  for (const id of expanded) linker.addConnection(links[id])
  linker.setConfig({ lines: { width: 3 } })
})

<VisualLinker> и useVisualLinker() уже пакетируют собственные обновления: одно обновление реестра за тик для блоков, помеченных директивами, и в движок передаются только изменившиеся соединения.

getStats() ​

ts
linker.getStats()
// { blocks, connections, rendered, culled, proxied, lastRenderMs, medianRenderMs, observedElements }
  • blocks, connections — сколько зарегистрировано.
  • rendered — сколько соединений записано в DOM за последний проход.
  • culled, proxied — скрыто отсечением, нарисовано к запасному блоку.
  • lastRenderMs, medianRenderMs — время последнего прохода и медиана по последним 60.
  • observedElements — элементов под ResizeObserver, включая контейнер.

Метод ничего не измеряет в DOM, поэтому его безопасно вызывать на каждом кадре. В Vue stats() отдаёт компонент и возвращает useVisualLinker(); он не реактивный.

Группа performance ​

  • cull — boolean | { margin?: number } · по умолчанию: false. Соединения, которых не видно, не рисуются: ни один конец и ни один участок между ними не доходит до видимой области (контейнера, его прокручиваемых предков и окна), расширенной на margin px (по умолчанию 64) и на запас под изгиб. Отсечённое соединение остаётся в модели, записи в layout у него нет, а когда оно возвращается, рисуется снова.
  • maxConnectionsForJumps — number · по умолчанию: 150. Когда мостики просят больше этого числа соединений smoothstep, мостики отключаются: поиск пересечений растёт вместе с числом отрезков.
  • maxRoutingNodes — number · по умолчанию: 6000. Размер сетки поиска маршрутизации в обход блоков, выше которого линия остаётся на обычном маршруте.
  • maxObstacleBlocks — number · по умолчанию: 200. Если вокруг соединения больше блоков, его не обходят.

Замеры ​

pnpm test:perf в репозитории запускает стенд playground/bench.html в Chromium и пишет docs/PERFORMANCE.md; при превышении порога он падает. Chromium, headless, ноутбук, без троттлинга; время в мс, один refresh() без изменений, если не сказано иное.

Сценарий0.4.30.4.5Порог
100 блоков, 100 связей, медиана / p952,1 / 2,80,7 / 1,3≤ 4 / ≤ 8
300 блоков, 300 связей, медиана5,72,2≤ 12
FPS при перетаскивании блока с 20 линиями, 300 блоков59,860,6≥ 55
FPS при прокрутке колонок по 200 блоков, 100 линий60,960,3≥ 55
Первая отрисовка, 1000 блоков, 500 связей4739≤ 400
1000 блоков без связей: наблюдаемых элементов100111
Тяжёлое оформление¹, 100 / 100, медиана10,02,6—
Тяжёлое оформление¹, 300 / 300, медиана41,05,9—
Тяжёлое оформление¹, 300 / 300, FPS при перетаскивании13,548,6—

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

Советы ​

  • На больших диаграммах включите performance.cull и оставьте clipToScrollParents.
  • Для множества линий выбирайте bezier или straight; smoothstep с обходом блоков и мостиками — самое дорогое сочетание.
  • Сворачивайте деревья через запасные концы, а не удаляя и добавляя соединения заново.
  • При прямой работе с движком группируйте изменения через batch().