Kirk Ross
Kirk Ross

Reputation: 7163

Javascript - correct way to wait for super long loop?

Maybe this is an async / await situation but I thought async was mainly for api calls(?)

How do you wait a long loop to finish, like this:

let x;
for (i = 1, i < 10000000000000000, i++) {
  x += (i * 99999);
}

console.log(x);

Upvotes: 1

Views: 1168

Answers (2)

vp_arth
vp_arth

Reputation: 14992

I thought async was mainly for api calls(?)

There are two different concepts related to the async word:

  • async/await functions Syntax sugar for receive Promises results in syncronous manner
  • real asynchronous behavior XHR api calls, delayed execution, event handling

async/await function does not make your function execution asynchronous automagically.

const foo = async (i) => { console.log('foo running', i); return i == 0 ? 42 : await foo(i-1); };
console.log('foo before')
foo(5)
  .then(x => console.log('foo', x))
console.log('foo after')

// foo before
// foo running 5
// foo running 4
// foo running 3
// foo running 2
// foo running 1
// foo running 0
// foo after
// foo 42

Javascript is one-threaded, all concurrent tasks must be splitted into async chunks to have any chance to other to work.

So, you should split your sync loop to many async parts to not to be frozen.

For example(I reduce params to have not too much time for wait):

async function calcX() {
  let x = 0;
  function iteration(i) {
    x += (i * 99999);
    if (++i >= 10000) return Promise.resolve(x);
    return new Promise((resolve) => {
      setTimeout(() => iteration(i).then(resolve), 0);
      // or requestAnimationFrame
    });
  }
  return await iteration(1);
}
const start = Date.now();
calcX()
  .then(x => console.log(x, Date.now() - start), err => console.error(err));

// 4999450005000 42465
It can be too slow if you put each iteration to event loop. So you can optimize it by batching of them(see @Steve's answer)

Or use WebWorker for your heavy sync task

Upvotes: 2

Steve
Steve

Reputation: 10906

You can convert long running synchronous functions into asynchronous functions by checking to see if a set amount of time has elapsed, and then coming back to the function later (achieved in this example via setTimeout):

var lastBreak = Date.now()

function takeABreak() {
    return new Promise(resolve=>setTimeout(resolve));
}

async function maybeTakeABreak() {
    if (Date.now() - 17 > lastBreak) {
        lastBreak = Date.now();
        await takeABreak();
    }
}

async function myLongLoop() {
    let x = 0;
    for (let i = 1; i < 100000000000000; i++) {
       await maybeTakeABreak();
       x += (i * 99999);
       if (!(i%1000000)) {
          console.log(i);
          // alternatively you could run `await takeABreak();` here
       }
    }
    return x;
}
myLongLoop().then(x=>console.log(x));

Upvotes: 1

Related Questions