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:
Use a web worker (as you indicated).
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:
postMessage the array to the worker (transferring if possible).
Have the worker send updates on its progress that you use to update the UI.
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:
Build a new array containing only the information needed for sorting purposes, along with the original index of each object in the array.
postMessage that array to the web worker.
Have the worker send updates on its progress that you use to update the UI.
Have the worker postMessage the sorted array back to your code.
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.
sortcallbacks can't beasyncfunctions. Of course, if you implement a custom sort...