JavaScript. Как сделать невероятно быстрый многопоточный Data Grid на 1 000 000 строк. Часть 2/2: р…
- пятница, 2 мая 2025 г. в 00:00:06
Часть 1 Работа с DOM | Часть 2 Работа с потоками
Особенности Fast Data Grid:
Невероятно быстрый
Многопоточный
Работает на пк и телефонах
Всего 523 строчки кода
Нет зависимостей
Vanilla JavaScript
Попробуйте скролл и поиск по 1 000 000 строк - Fast Data Grid.
В статье расскажу про работу с потоками.
Долгие вычисления блокируют UI.
Задачи в потоке выполняются последовательно. Пока текущая задача не завершится, следующая задача не будет выполняться. Обработка кликов мышкой, скролла - это тоже задачи.
Поиск по 1 000 000 строк - это долго. Пока идет поиск, браузер не будет реагировать на действия пользователя. Браузер “зависнет”. Чтобы убрать зависание, можно вынести поиск в отдельный поток.
Просто вынести поиск в отдельный поток не достаточно. UI не будет зависать, но результаты поиска будут отображаться также долго. Нужно показывать результаты частями по мере готовности. Fast Data Grid сразу отображает первые 100 строк. Пока вы скроллите, Fast Data Grid ищет следующие строки в отдельном потоке.
Только основной поток браузера имеет доступ к DOM. Значит только основной поток может отобразить результаты поиска. Поэтому результаты из потока поиска нужно передавать в основной поток.
Данные между потоками передаются долго. Поэтому передавать массив строк грида со всеми данными для отображения неэффективно.
Эффективно передавать можно только некоторые типы данных. Такие типы данных называются “Transferable objects”. Transferable objects” при передаче между потоками не клонируются, а передаются по ссылке. Uint32Array это “Transferable object”. Мы можем использовать Uint32Array, чтобы передать индексы строк грида.
Поиск по миллиону строк - это долго. Если пользователь меняет строку поиска, нужно как можно скорее прервать предыдущий поиск и начать новый. Способа прервать операцию нет. Но можно разбить поиск на подзадачи. Между подзадачами проверять изменилась ли строка поиска.
setTimeout ставит задачу в конец очереди. См. листинг 1.
setTimeout(_ => console.log(1), 0);
console.log(2);
result
2
1
Листинг 1. setTimeout ставит задачи в конец очереди. В начале в консоле будет 2, потом 1.
В листинге 2 поиск идет по блокам в 5 000 строк. В конце блока setTimeout позволяет потоку среагировать на изменение newStr.
export const wait = () =>
new Promise(resolve => setTimeout(resolve, 0));
await arrForEachChunk(
data,
// chunkSize
5_000,
// forEachCallBack
(row, index) => { /* search */ },
// chunkEndCallBack
async () => {
await wait(); // let other tasks go
if (_str !== newStr) {
return false; // stop search
}
return true; // continue search
}
);
Листинг 2. Поиск идет по блокам в 5 000 строк. В конце блока setTimeout позволяет потоку среагировать на изменение newStr
arrForEachChunk - это моя утилита, она есть в репозитории.
Делаю самый красивый редактор блок-схем DGRM.net.
Проверьте сами.
Ставьте звездочки на GitHub.