I have a function, that looks like this.
function () {
longArray.forEach( element => doSomethingResourceIntensive(element))
}
Because the array is long and the function is a little resource intensive, it freezes the browser.
Now I want to rewrite it using Promises, so it does the same thing, just not freezing the browser, and I want the solution to be elegant and "ES6-y"; ideally, the function would return Promise when all the iterations finished.
I found this question, where it's dealt with using setTimeout, but it seems a little "un-ES6-y", and it doesn't return a Promise.
I cannot do
function () {
return Promise.all(longArray.map( element =>
Promise.resolve().then(() => doSomethingResourceIntensive(element))
)
}
because I need to run the promises in succession and I am not sure if it would happen there.
If you need to run promises in succession, you want to chain the .then
calls. You normally do that with .reduce()
:
function () {
return longArray.reduce((promise, el) =>
promise.then(() => doSomethingResourceIntensive(el)),
Promise.resolve()); // Start with a clean promise!
}
Also, depending on the type of job you do, you may want to have a look into Web Workers, which are executed in another thread and thus don't block the page.
The answer you reference is right, you need setTimeout
. Using a promise-chain alone wont help because .then
chains execute on a microtask queue, which in most browsers are emptied completely at the tail of the current run-to-completion. In other words, they'll still freeze things.
If you want something ES6-y, I rely on this trusty helper:
var wait = ms => new Promise(resolve => setTimeout(resolve, ms));
Then I can do this:
longArray.reduce((p, i) => p.then(() => doIntensiveStuff(i)).then(() => wait(5)),
Promise.resolve());
Unless you can use workers of course.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With