1

I am new to Node.js and was trying to understand async and await terms.

In the process, I got to know about Promise.

As I understood, with the help of it, we can make the function non-blocking.

I tried the following code,

function get() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            let out = 0
            const n = 9_900_000
            console.log('start looping')
            for (let i = 0; i < n; i++) {
                out += Math.cos(i)
            }
            console.log('done looping')
            resolve(out)
            console.log('resolved')
        })
    })
}

console.log('before function calling')
r = get()
console.log('After function calling')
r.then(console.log)
console.log('in the end of file')

We find that get is behaving like a non-blocking function.


function get() {
    return new Promise((resolve, reject) => {

        let out = 0
        const n = 9_900_000
        console.log('start looping')
        for (let i = 0; i < n; i++) {
            out += Math.cos(i)
        }
        console.log('done looping')
        resolve(out)
        console.log('resolved')
    })
}
console.log('before function calling')
r = get()
console.log('After function calling')
r.then(console.log)
console.log('in the end of file')

In other words, I removed the setTimeout.

Now the get becomes a blocking function.

Why is this happening?

  • 1
    function passed to the promise constructor is called _synchronously_. – Yousaf Jul 03 '21 at 07:08
  • 3
    Promises don't run on a separate thread or anything like that. A promise is *only* a notification mechanism for async tasks. But a lot of async tasks are just running on the same thread. You've written code that blocks the thread for a while, so it will...block the thread for a while. And then send a notification it's done via the promise. – VLAZ Jul 03 '21 at 07:09
  • 1
    There are no "threads" in JS, and once some syncronous code (like your `for`) started to execute it will run until it's finished. In the meantime no other code will be able to run because JS is in fact single threaded ... – derpirscher Jul 03 '21 at 07:10
  • 1
    Probably relevant: [Please point out the misfacts in my learning regarding Asynchronous Javascript](https://stackoverflow.com/q/65833787) – VLAZ Jul 03 '21 at 07:10

1 Answers1

9

The promise executor function executes synchronously, meaning that the code inside of the function below:

new Promise(() => { // promise "executor function" that executes synchronously

});

executes when the Promise is created (the function is executed by the Promise constructor). In your second example, since your for loop is blocking, the promise is only created once your for loop completes, and only once it is created is it returned from get(), making it block the execution of any other code that comes after your call to the get() function.

In your first example, the promise executor function is still run synchronously when you create your promise, but this time, your calling setTimeout() with a delay of 0. This makes the callback that you passed to setTimeout() get queued on the task queue, and it will only execute once your main script has finished executing. This means that when your Promise is returned from your get() function, the for loop inside of your setTimeout() callback hasn't started running yet, as the callback passed to setTimeout() hasn't been executed/ran yet due to there still being code that needs to be run in the main script. As a result, your other code (such as the console.log()s) can run as there is nothing blocking them. Only once your main script is complete, then is your callback previously queued by setTimeout executed.

Keep in mind that Promises aren't a tool for making synchronous code asynchronous, they're more of a tool to help developers deal with code that already behaves asynchronously. If you need to perform a blocking operation in a background thread to prevent blocking the main thread then you can consider using a web worker.

Nick Parsons
  • 45,728
  • 6
  • 46
  • 64