Виртуальная прокрутка
Почему это делает движок
Хвостовые задержки виртуальных списков на DOM берутся из цепочки: событие прокрутки возвращается в главный поток, вызывает setState, затем diff, затем переразметку. Как только главный поток занят, кадры теряются.
doper переносит расчёт окна в ядро: установившаяся прокрутка никогда не вызывает оболочку. Оболочка лишь материализует видимый диапазон по окну прогрева, которое спланировало ядро; если данные ещё не готовы, рисуется заглушка, а на следующих кадрах она дополняется.
Использование
createElement("virtualList", {
width: 480,
height: 640,
itemCount: 1_000_000,
estimatedItemHeight: 32,
renderItem: (index: number) =>
createElement("container", {
width: 480,
height: 32,
children: createElement("text", { value: `Строка ${index}` }),
}),
});estimatedItemHeight — только начальная оценка. Когда измерена настоящая высота, ядро корректирует положение якоря через дерево префиксных сумм (Фенвика), и позиция прокрутки не прыгает.
Настраиваемые параметры
| prop | Действие |
|---|---|
baseOverscanViewports | Симметричный диапазон прогрева (в единицах вьюпорта) |
velocityHorizonSeconds | Горизонт проекции скорости для предсказания направления |
maximumAheadViewports | Предел прогрева в одном направлении |
scrollX / scrollY | Программная позиция прокрутки (ScrollTo только при изменении) |
Предсказание направления при быстром броске прогревает прежде всего сторону движения, а не тратит бюджет симметрично на обе.
Программная прокрутка
// Изменение свойства порождает ровно одну мутацию ScrollTo
root.render(createElement("virtualList", { scrollY: 500_000 * 32 /* ... */ }));Либо API прямого управления на root — для собственных жестов:
root.beginScroll(handle);
root.scrollBy(handle, 0, deltaY, elapsedMs);
root.endScroll(handle); // оценку скорости броска берёт на себя ядроhandle приходит из колбэка ref элемента (NodeHandle).
Колесо и трекпад
Расстояние прокрутки колесом совпадает с браузерным, но кривая передачи разделяется по источнику ввода: дельты высокой точности (трекпад) применяются 1:1 сразу, а инерцию по-прежнему поставляет поток событий операционной системы; дискретные щелчки колеса накапливаются в анимационную цель, к которой движение идёт по экспоненциальному замедлению, жёстко ограничивается границами содержимого и не даёт перепрокрутки — ровно как в браузере.
Вложенность и редактирование
Если перетаскивание указателя началось на редактируемом тексте, выделение текста имеет приоритет над перетаскиванием прокрутки; колесо по-прежнему прокручивает ближайшего прокручиваемого предка. Этот приоритет определяется глубиной пути попадания и не требует вмешательства приложения.
Критерий производительности
Автоматический бенчмарк на фиксированной фикстуре (миллион строк, 20 000 кадров) входит в набор проверок при слиянии. Сейчас P95/P99 воспроизведения меньше микросекунды, а тридцать минут непрерывной прокрутки не показывают неконтролируемого роста памяти.
P95/P99 на реальных устройствах и задержка ввода относятся к квалификации платформы и не являются условием завершения инженерных работ. Эта граница проведена намеренно: она не даёт невоспроизводимым данным с устройств блокировать работу и в то же время не позволяет выдавать инженерные цифры за обещание для устройств.
В демонстрации прокрутки в Playground видны покадровые метрики в реальном времени.