Реагируйте, как сделать большие операции (например, фильтрацию и сопоставление массива из 10000 строк) асинхронными, чтобы избежать блокировки пользовательского интерфейса?

avatar
nick
1 июля 2021 в 20:05
61
1
0

У меня есть таблица с большим количеством данных, и когда вы выбираете фильтр, данные должны быть отфильтрованы и сопоставлены снова, что занимает около 1 или 2 секунд, но в течение этого времени пользовательский интерфейс блокируется. Есть ли способ сделать это «асинхронно» и, возможно, показать индикатор загрузки во время обработки? Я ищу универсальное решение. Спасибо!

Источник
Matt
1 июля 2021 в 20:09
1

Вы смотрели на виртуализированные? github.com/bvaughn/react-virtualized

nick
1 июля 2021 в 20:13
0

@Matt, насколько я понимаю, предназначен для рендеринга многих вещей, чтобы браузер не тормозил, но в моем случае фактический рендеринг не так уж важен, потому что таблица разбита на страницы. Моя проблема заключается в обработке данных, а не в их рендеринге.

raina77ow
1 июля 2021 в 21:28
1

Это может быть (слегка) связано. Хотя вопрос касается Node, примеры, приведенные в этом ответе, работают в браузере.

raina77ow
1 июля 2021 в 21:28
1

И этого тоже, конечно.

zero298
1 июля 2021 в 21:32
0

Реальные функции обработки занимают секунды? Если вы блокируете пользовательский интерфейс из-за этого, вам нужно получить что-то еще для вычислений. Либо бэкенд, либо сервис-воркер. Сервисные работники могут выполнять длительные функции без блокировки, а затем выдавать данные по их завершении. Однако неясно, будет ли это работать для вас или нет.

zero298
1 июля 2021 в 21:39
2

Извините, веб-воркеры, а не сервис-воркеры.

Ответы (1)

avatar
Prakhar Pal
3 июля 2021 в 19:49
1

Асинхронный цикл for может выглядеть следующим образом

const loopAsync = (arr, { chunkSize = 1000 }, processFn, onFinish) => {
    const handleProcessing = index => {
        if (index >= arr.length) {
            onFinish();
        } else {
            const end = Math.min(index + chunkSize, arr.length);
            for (let i = index; i < end; i++) {
                processFn(arr[i], i);
            }
            setTimeout(() => {
                handleProcessing(end);
            },0);
        }
    }
    handleProcessing(0);
}

chunkSize из 1000 достаточно, я думаю, но, вероятно, может быть 10 000 и не должно влиять на пользовательский интерфейс.

и это можно вызвать следующим образом

// setup code
const filterFunction = item => item > itemCount / 2;
const asyncResult = [];
const asyncProcessingFunction = num => {
    if(filterFunction(num)) asyncResult.push(num);
}
//actual loopAsync invocation
//show loader here
loopAsync(items, { chunkSize: 5000 }, asyncProcessingFunction, () => {
    // hide loader here
    // and do something with results e.g. asyncResult in this case.
});