First thing’s first
Using promises/async tasks tends to be slow when there’s a large amount of small tasks to be done. Proof of this won’t be provided here, since there’s plenty of great posts on this already. Using a traditional for/while loop can be a lot quicker, at the expense that it blocks the event loop until its done.
If you have something highly iterative, and don’t want to lock up the event loop - executing work in batches may work best.
We can batch the workload into chunks of at most size ITERATIONS_PER_BATCH
and execute them asynchronously using setTimeout()
. This way, we can still multitask other things while the algorithm is running while retaining most of the performance of a native loop. By wrapping it in a Promise, you can await
it or use like you normally would.
Let’s use both!
With this, there’s a couple things to note. You can add variables outside of innerTask
for keeping state between batches. One final note which is left as an exercise to the reader, is to add an exit condition depending on what you are doing. Without it, this will loop infinitely.
// you can play with this value, greatly depends on how fast/slow your code is.
// this is the number of iterations will run in each batch, at most.
const ITERATIONS_PER_BATCH = 100
async function doSomethingBig () {
return new Promise((resolve, reject) => {
const innerTask = () => {
for (let i = 0; i < ITERATIONS_PER_BATCH; i++) {
// DO YOUR STUFF HERE
// declare variables outside of innerTask and use for keeping state between tasks
}
// TODO: make sure you add an exit condition,
// this setTimeout() queues the next batch to be processed.
setTimeout(innerTask, 0) // schedule subsequent tasks
}
setTimeout(innerTask, 0) // run first task
})
}