0

I'm sorting a large array and want to update the UI in my web app while sort is running. In my custom comparison function, I'm updating the HTML content every 10,000 (or so) comparisons, but the browser doesn't reflect these changes.

large_array.sort( (a,b) => {
    ++comparisons
    if( comparisons % 10000 == 0 ) {
        // this works:
        console.log(comparisons)
        // this doesn't:
        document.querySelector('#sort-progress').textContent = comparisons
    }
    return custom_sort(a,b)
})

What I've found is that using web workers should be the "correct" solution, but that would mean to completely redesign the application. So I hope to find some workaround.

3

1 Answer 1

6

Your current approach doesn't work because the JavaScript code runs on the main UI thread, and ties it up until the sort is complete, so the browser can't update the page display until the sort is over and the JavaScript code finishes running, allowing the event loop to complete.

A few options come to mind:

  1. Use a web worker (as you indicated).

  2. Sort the array in chunks, yielding back to allow the browser to repaint before triggering sorting the next chunk with setTimeout(..., 0) or similar. Don't yield too often or you'll end up taking forever to sort the result, but every once in a while should be good.

    • One way to do that is to write your own sort function (perhaps implementing a Timsort) and implement it as an async function, occasionally (for instance, roughly every 10,000 elements) yielding to allow the browser to perform display updates by doing await delay(0) where delay is a wrapper for setTimeout.

What I've found is that using web workers should be the "correct" solution, but that would mean to completely redesign the application

That will depend a lot on what you're sorting. If you're sorting anything transferrable or that can be serialized with the structured clone algorithm, it shouldn't be necessary to completely redesign the application just for this. You need to:

  1. postMessage the array to the worker (transferring if possible).

  2. Have the worker send updates on its progress that you use to update the UI.

  3. Have the worker postMessage the sorted array back to your code.

But if what's in the array can't be handled that way, there will indeed be more work involved. For instance, you might:

  1. Build a new array containing only the information needed for sorting purposes, along with the original index of each object in the array.

  2. postMessage that array to the web worker.

  3. Have the worker send updates on its progress that you use to update the UI.

  4. Have the worker postMessage the sorted array back to your code.

  5. Loop through the received array either putting the elements in the place they should go (e.g., doing swap operations), or building a new array with the elements in the order they should go.

That said, though, implementing Timsort as an async function with periodic pauses may well be simpler.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.