2

I have the following code:

function asyncLoop() {
    return new Promise(function(res, rej) {
        for(let i=0;i<=400000000;i++) {
            if(i===400000000) {console.log("done"); res();}
        }
    });
}

asyncLoop().then(()=>{console.log("then")});
console.log("out");

I am getting the following output:

done
out
then

According to my understanding of Promises, the asyncLoop should have run asynchronously and the following should have been the output:

out
done
then

What am I missing?

dhdhagar
  • 121
  • 1
  • 7
  • https://stackoverflow.com/a/5436869/1278540 then vs done – Debajyoti Das May 26 '17 at 12:32
  • 1
    @DebajyotiDas that is about jQuery promises - this uses native. – Jamiec May 26 '17 at 12:33
  • Promises have no "magic" properties to making something asynchronous that isn't already asynchronous. They are merely a standardized notification and error handling scheme - nothing more. If the underlying operation is not asynchronous, then wrapping it in a promise will NOT somehow make it become asynchronous. – jfriend00 May 26 '17 at 17:51
  • @jfriend00 disagreed - callback passed to `then()` is guaranteed to be called asynchronously even if the promise is already resolved – Kos May 27 '17 at 18:26
  • @Kos - Yeah, I knew someone would bring that up. That doesn't make the operation itself asynchronous. It just delays when the `.then()` handler is called and it has nothing to do with what the OP was confused with in this question as we can see by your own answer. People somehow think that promises can magically change a synchronous operation into an asynchronous operation. They don't do that. Yes, `.then()` is called on the next tick, but that doesn't change at all when the actual code before it is executed. If it was synchronous, it's still synchronous. That's the point to the OP. – jfriend00 May 27 '17 at 18:27
  • @Kos: jfriend00 seems to be spot on about this. Tried a simplified snippet to test it out. The only way to concretely execute asynchronous code seems to be using Web Workers. – dhdhagar May 28 '17 at 07:30
  • @delfuego17 if your goal is to run calculations in a background thread, then yes. That's not the usual meaning of 'asynchronous' though. Have a look at Rob Pike's "Concurrency is not parallelism". Promises are for concurrency, not for parallelism – Kos May 28 '17 at 09:39

3 Answers3

3

Your loop is inside the callback that you passed to new Promise. This function is called the 'executor':

function executor(resolve, reject)

The executor is called synchronously by new Promise. The role of the executor is to set up any asynchronous events in order to have resolve or reject eventually called.

See MDN: Promise constructor parameters

This function is invoked immediately with the resolving functions as its two arguments.

The constructor will not return until the executor has completed

Kos
  • 70,399
  • 25
  • 169
  • 233
1

You've made a wrong assumption. Promises are not meant to be async, they are used in an async context to bring an easier way to handle the calls. To make a process "kind of async", you could use setTimeout().

function asyncLoop() {
    return new Promise(function(res, rej) {
        setTimeout(function() {
            for(let i=0;i<=400000000;i++) {
                if(i===400000000) {console.log("done"); res();}
            }
        }, 0);
    });
}

asyncLoop().then(()=>{console.log("then")});
console.log("out");
Booster2ooo
  • 1,373
  • 9
  • 11
  • 1
    JavaScript is single-threaded and this blocks the main browser thread just as much as the original question, only on the next run of the event loop. – jib May 26 '17 at 22:37
  • Indeed @jib, you're right. It's not really async, just delayed. – Booster2ooo May 27 '17 at 08:03
1

A promise is just a return value one attaches callbacks to instead of passing callbacks into a function, a convention with several benefits. See Using promises on MDN for more.

JavaScript is single-threaded with an event loop. .then and setTimeout schedule events.

All JavaScript runs on the browser's main thread, unless you create a worker:

function asyncLoop() {
  for (let i = 0; i <= 400000000; i++) {
    if (i == 400000000) {
      self.postMessage('done');
    }
  }
}

var blob = new Blob(["onmessage = " + asyncLoop.toString()],
                    {type: "text/javascript"});

var worker = new Worker(window.URL.createObjectURL(blob));

worker.onmessage = e => console.log(e.data);
worker.postMessage("start"); 
jib
  • 40,579
  • 17
  • 100
  • 158