JavaScript. Как сделать невероятно быстрый многопоточный Data Grid на 1 000 000 строк. Часть 1/2: н…
- суббота, 30 ноября 2024 г. в 00:00:10
Особенности Fast Data Grid:
Невероятно быстрый
Многопоточный
Всего 523 строчки кода
Нет зависимостей
Vanilla JavaScript
Попробуйте скролл и поиск по 1 000 000 строк — Fast Data Grid.
В статье перечислю нюансы работы с DOM. Про многопоточность в следующей статье.
Браузер медленно отрисовывает большое DOM-дерево. 1 000 000 строк высотой 20 px браузер вообще не нарисует — максимальная высота DIV в Chrome 15 000 000 px. Чем меньше HTML-элементов тем лучше.
Fast Data Grid добавляет в DOM столько строк, сколько поместятся на экране.
const rowsCount = Math.ceil(viewPortHeight / rowHeight);
Листинг 1. Подсчет сколько строк помещается на экран
Когда нужно вывести новые данные DIV-ы строк переиспользуются. Новые данные записываются в те же самые DIV-ы. Изменить содержимое DIV быстрей чем удалить DIV и создать новый.
При скроле позиция DIV-ов строк рассчитывается на JavaScript.
Для работы скролла, Fast Data Grid делает большой DIV. На этот DIV вешается событие scroll. Обработчик события scroll рассчитывает позицию DIV-ов строк.
Если суммарная высота строк больше 15 000 000 px, то DIV-ы строк должны крутиться быстрее чем большой DIV. Когда большой DIV докручивается до конца → DIV-ы строк тоже должны докручиваться до конца.
При скроле DIV-ов строк нужно применять коэффициент.
const scrollYKoef =
// if {allRowsHeight} > 15 million -> we have to applay koef on scroll
// if {allRowsHeight} <= 15 million -> {scrollYKoef} = 1
(allRowsHeight - viewPortHeight) / (scrolHeight - viewPortHeight);
listen(scrollOverlayDiv, 'scroll', /** @param {Event & {target:HTMLDivElement}} evt */ evt => {
const scrollTop = evt.target.scrollTop * scrollYKoef;
rowsDiv.style.transform = `translateY(${scrollTop}px)`;
});
Листинг 2. Применение коэффициента при скроле
При скроле позиция задается через transform translate. CSS transform translate быстрее чем CSS top.
<!-- transform быстрее -->
<div style="transform: translateY(-16px);"></div>
<!-- чем top -->
<div style="top: -16px;"></div>
Листинг 3. CSS transform translate быстрее чем CSS top
Браузер выводит фреймы на монитор так:
В начале отрабатывает JavaScript, потом рассчитываются стили, потом layout, потом отрисовка.
Если стандартный порядок не нарушать - браузер отрисует фрейм максимально быстро.
В начале цикла параметры DOM уже рассчитаны и соответствуют параметрам предыдущего фрейма. Например box.offsetHeight в начале цикла уже рассчитан. Но если изменить DOM и потом прочитать DOM → браузеру придется нарушить стандартный порядок. Потребуется лишний раз рассчитать layout.
box.classList.add('super-big');
// Gets the height of the box in pixels and logs it out:
console.log(box.offsetHeight);
Листинг 4. Изменение DOM перед чтением DOM. Плохо. Приводит к layout thrashing.
Лишний перерасчет Layout называется «layout thrashing».
Визуальная демонстрация, как изменение DOM перед чтением замедляет браузер:
https://wilsonpage.github.io/fastdom/examples/animation.html
Отличная статья по теме:
Avoid large, complex layouts and layout thrashing | Articles | web.dev.
Делаю самый удобный редактор блок-схем DGRM.net.
Он же самый удобный сервис для бизнеса: Excel + схемы бизнес процессов.
Ставьте звездочки на GitHub.