Home > Net >  Why des Node JS not execute Asynchronous Function at all?
Why des Node JS not execute Asynchronous Function at all?

Time:07-13

Please consider this example -

P.S - findByIdAndRemove is a Mongoose Function, used to deal with MongoDB.

Block 1 :-

try {
        Product.findByIdAndRemove(prodId);
        console.log("Product Deleted");
} catch (err) {
//...
}

Block 2 :-

try {
        await Product.findByIdAndRemove(prodId);
        console.log("Product Deleted");
} catch (err) {
//...
}

While trying to delete a product, if I use Block 1, the product wont be deleted. But the console.log will be executed.

However, while trying to use Block 2, the product WILL be deleted and then console.log will be executed.

Now, I understand that Nodejs, being Asynchronous, will not wait for Product Deletion to be completed. That is the reason why console.log is executed. In Block 2, we are forcing Node JS to wait for the Async function, i.e the Delete Request to be over, before the next statement , i.e console.log is executed.

However, let's say I do not use Async....Await or Promise or Callback, as in Block 1. Irrespective of the Asynchronous execution, shouldn't Node JS execute the query even though it moves to the next statement. What I mean is, it is clear that Node will not wait for Product Deletion to occur. It will execute that, and proceed to console.log. But, it should still execute the Product Deletion at some point. However, even after waiting for sometime, I found that Node JS does NOT execute Asynchronous functions at all, unless it is executed Synchronously (using Async await, or promise, etc.).

So, my question is, why does Node JS stop executing Asynchronous functions completely, rather than completing that execution after a certain time, unless handled synchronously using Async..await or Promise or Callbacks.

CodePudding user response:

This is an expansion on my comment.

While trying to delete a product, if I use Block 1, the product wont be deleted. But the console.log will be executed.

However, while trying to use Block 2, the product WILL be deleted and then console.log will be executed.

As you know, the only difference there is that await is left out. Realize what await is: it is nothing but "syntactic sugar", or in other words, a nicer looking but technically equivalent way of using .then() and .catch(). It is not magic.

This is important for later.

Now, I understand that Nodejs, being Asynchronous, will not wait for Product Deletion to be completed. That is the reason why console.log is executed. In Block 2, we are forcing Node JS to wait for the Async function, i.e the Delete Request to be over, before the next statement , i.e console.log is executed.

If findByIdAndRemove (without await, then(), or a callback) fired off some work and returned a Promise, then that would be true. But note the if. That's not what's happening here.

However, let's say I do not use Async....Await or Promise or Callback, as in Block 1. Irrespective of the Asynchronous execution, shouldn't Node JS execute the query even though it moves to the next statement.

It could, but the library doesn't have to execute a query at that time.

What I mean is, it is clear that Node will not wait for Product Deletion to occur. It will execute that, and proceed to console.log. But, it should still execute the Product Deletion at some point.

And here's the crux of the issue:

The delete function doesn't delete a record and then return a promise.

Rather:

The delete function returns an object with a then() method. Only when its then() method is called will something happen.


To demonstrate, let's make a very simple fake (SQL) query builder.

class Query {
  constructor(table) {
    console.log("Starting a new query (nothing async is happening)");
    this.table = table;
  }
  findById(id) {
    console.log("Adding a where filter (nothing async is happening)");
    this.whereFilter = `WHERE id = ${id}`;
    return this;
  }
  sort(by, asc = true) {
   console.log("Adding a sort option (nothing async is happening)");
    this.sortOption = `ORDER BY ${by} ${asc ? 'ASC' : 'DESC'}`;
    return this;
  }
  limit(n) {
    console.log("Adding a limit option (nothing async is happening)");
    this.limitOption = `LIMIT ${n}`;
    return this;
  }
  toString() {
    return `
      SELECT *
      FROM ${this.table}
      ${this.whereFilter || ''}
      ${this.sortOption  || ''}
      ${this.limitOption || ''}
    `.trimEnd();
  }
  then(cb) {
    // The user has called .then() or `await` on this instance.
    // Only now execute the database query.
    // We'll use a timeout to fake latency.
    // This always returns the same fake user.
    console.log(`Now executing an async task`);
    console.log(`querying the database for: ${this.toString()}`);
    return new Promise(resolve =>
      setTimeout(resolve, 1000, [{id: 7, name: "Example User"}])
    ).then(cb);
  }
}

Now for some tests:

  const user1 = await new Query("users").findById(1);
  console.log("(Result of query 1) Found user", user1);

  new Query("users").findById(7).then((user2) => {
    console.log("(Result of query 2) Found user", user2);
  });
  console.log(`Because we don't await this promise, 
  it can resolve at any time in the future.`);

This is intuitive and works as you'd expect.

  // Until the query is awaited / then() is called, 
  // there are no asynchronous processes.
  const query = new Query("users");
  query.limit(10);
  query.findById(77);
  query.sort("name");
  const user3 = await query;
  console.log("(Result of query 3) Found user", user3);

Until await is done, the database (or in this example, the timeout) is not even touched in any way. We "build up a query" and only later execute it.

  // await / then() at any time.
  const query2 = new Query("users");
  query2.limit(10);
  const user4 = await query2;
  console.log("(Result of query 4) Found user", user4);

  // Or even like this.
  const query3 = new Query("users").limit(10);
  const user5 = await query3.sort("id", false);
  console.log("(Result of query 5) Found user", user5);

More of the same.

  • Related