1

Let say I have this module :

export async function beFancy () {
  let i, j, load;
  // just for trying to delay the return;
  for (i = 0; i < 999; ++i) {
    for (j = 0; j < 999; ++j) {
      load = i + j;
    }
  }
  return 'beFancy finished';
}

now I make a main module for testing :

import {beFancy} from './mymodule';

beFancy().then((msg) => console.log(msg));
console.log('main finished');

If I execute, the output is as expected

-> main finished
-> beFancy finished

because beFancy is -asynchronous-

But now if I try to make the loop a little more intense :

export async function beFancy() {
  let i, j, load;
  for (i = 0; i < 9999999; ++i) {
    for (j = 0; j < 999; ++j) {
      load = i + j;
    }
  }
  return 'beFancy finished';
}

and executing main again, the output is the same

-> main finished
-> beFancy finished

but I would expect main finished to display before the function beFancy is actually being processed. Instead the above output displays in one shot when beFancy finish. At first I thought the reason was because the output is only flushed at the end of the program but if I type :

console.log('begin');
beFancy().then((msg) => console.log(msg));
console.log('main finished');

"begin" displays before 'beFancy' executes, so my previous assumption is not met.

So because beFancy is -asynchronous- what could possibly be wrong ? Is it an unexpected behavior on my machine ?

2 Answers 2

1

So because beFancy is -asynchronous- what could possibly be wrong ?

That's because it's only beFancy returned value that is asynchronous. beFancy is mostly synchronous and blocks main thread. The code above is roughly same as:

  function beFancy () {
    return new Promise(resolve => {
      let i, j, load;
      for (i = 0; i < 999; ++i) {
        for (j = 0; j < 999; ++j) {
          load = i + j;
        }
      }
      console.log('logged on same tick')
      resolve('logged on next tick');
    });
  }

  console.log('begin');
  beFancy().then((msg) => console.log(msg));
  console.log('main finished');

In order for a loop in async function to be asynchronous and non-blocking, it should be performed in chunks with await:

export async function beFancy () {
  let i, j, load;
  for (i = 0; i < 999; ++i) {
    await null; // next tick
    for (j = 0; j < 999; ++j) {
      load = i + j;
    }
  }
  return 'beFancy finished';
}
Sign up to request clarification or add additional context in comments.

Comments

0

JavaScript runs on a single thread. It achieves performance parity (and sometimes superiority) over multi-threaded languages by taking advantage of asynchronous non-blocking I/O.

This works because most of the time, in multi-threaded languages, the application thread is sitting idle waiting for an async I/O request to return. In JavaScript, that waiting request is parked and the thread continues execution elsewhere.

This is great when you're waiting on a network call or disk, but if your async request is chewing up CPU, the thread is sitting there with it chewing away. Therefore the code you have above for all intents and purposes performs synchronously.

Here's the execution order of the code:

  1. starts in main
  2. enters beFancy method
  3. sticks with the for loop in beFancy
  4. returns to the caller in main with the promise
  5. prints 'main finished'
  6. resolves the promise
  7. prints 'beFancy finished'

Replace your CPU intensive for loops with a setTimeout( () => console.log('done!'), 1500) and you should see the results you expect.

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.