1

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.

5
  • 1
    Nodejs, being Asynchronous - no, it isn't ... handled synchronously no, await doesn't mean "do this synchronously" - it means "do this in a way that looks synchronous, but isn't really, it's just to make coding easier" Commented Jul 13, 2022 at 9:04
  • Is Block 1 in some nodejs program that is running and doing other work, or is this in some quick script that you execute on the command line, which does what it does and exits back to the shell? Commented Jul 13, 2022 at 9:06
  • 1
    A promise is nothing more than an object that has a .then function property. The database library you're using is probably not executing the query until that .then() function is called, either explicitly or by using await. It's a way to make things like this fictitious example possible: await find(...); await find(...).sort(...).limit(1). Commented Jul 13, 2022 at 9:44
  • @JaromandaX I am using Mongoose , so I picked up a code from there. Commented Jul 13, 2022 at 10:57
  • That's nice. Not sure how that answers my question Commented Jul 13, 2022 at 11:06

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

10 Comments

Only when its then() method is called will something happen. that's not how promises work
Don't think such absolutes. Here, straight from the horse's mouth: Mongoose only executes a query (with .this.exec()) when the .then() of a Query object is called.
Mongoose query objects aren't promises
@RickN that's not how Promises work. Clearly, mongoose returns a thenable rather than a Promise 🤪 so. I stand by my assertion. However, that makes your answer not only correct but valuable information worthy of an upvote. I should've read your answer thoroughly
@JaromandaX But that's exactly what my answer says: it doesn't return a Promise it returns an object with a then method.
|

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.