1

I have a table with a lot of data and when you select a filter, the data has to be filtered and mapped again, which takes about 1 or 2 seconds, but during that time, the UI gets blocked. Is there any way to do this "async" and maybe show a loading indicator while the processing is being done? I'm looking for an all-frontend solution. Thanks!

nick
  • 2,819
  • 5
  • 33
  • 69
  • 1
    Have you looked at virtualized? https://github.com/bvaughn/react-virtualized – Matt Jul 01 '21 at 20:09
  • @Matt as I understand it, that's for rendering a lot of things so that the browser doesn't become slow, but in my case, the actual rendering is not much cause the table is paginated. The problem of mine is processing the data, not rendering it. – nick Jul 01 '21 at 20:13
  • 1
    [That](https://stackoverflow.com/questions/67135336/easiest-way-to-make-a-cpu-bound-task-asynchronous-in-node-js/67135653#67135653) might be (slightly) related. While the question is about Node, the examples given in that answer are running in browser. – raina77ow Jul 01 '21 at 21:28
  • 1
    And [this one too](https://stackoverflow.com/questions/26615966/how-to-make-non-blocking-javascript-code), of course. – raina77ow Jul 01 '21 at 21:28
  • Are the actual processing functions taking seconds? If youre locking the UI up because of that, you need to get something else to do the calculations. Either the back end or a service worker. Service workers can do long running functions without blocking and then emit data when they are finished. Its not clear whether that will work for you or not though. – zero298 Jul 01 '21 at 21:32
  • 2
    Sorry, [web workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers), not service workers. – zero298 Jul 01 '21 at 21:39

1 Answers1

2

An async for loop might look as following

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 of 1000 is sufficient I think but it can probably be 10,000 and shouldn't affect the UI.

and this can be invoked as following

// 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.
});

Prakhar Pal
  • 178
  • 7