Search code examples
javascriptnode.jsmongoosees6-promise

How does mongoose's find() function hold on to its execution and wait for a later function in its chain to complete first?


I was going through some tutorial materials and I notice that in Mongoose, I could somehow defer the final execution of a promise in it but I wonder how that is done.

For example, I can call the find function and it returns the promise of the result likes so:

const blogs = await Blog.find({id : '123'});

The find() function in mongoose calls the exec() function in the Query object to complete the query and return the result, like in the line of this file.

Then, let's say that I have the following modifications to the prototype of the Mongoose Query object to see whether I should retrieve data from cache or from Mongo:

mongoose.Query.prototype.cache = function() {
   this.useCache = true;
   return this;
}

mongoose.Query.prototype.exec = async function() {
   if (!this.useCache) {    // <-- Apparently, I don't understand how this.useCache can be true if this.cache() was called
      this.exec.apply(this, arguments);
    }
    return 'some cached value';
    return this;
}

// Somehow, the find() section of the chaining is capable of waiting for cache() which is called later to complete to know that useCache is true! But how is that done?
const blogs = await Blog.find({id : '123'}).cache();  // <-- how did this mange to return 'some cached value'?

However, since exec() is already called and evaluated in find() which is executed before the cache() function in the chain, how could this.useCache still be eventually evaluated in the exec() function finally when it resolves?

Unless there are some ways to wait until everything else down the chain have finished executing, in this case find() waited for cache() to finish executing, I would have expected this.useCache to always be undefined, wouldn't it?

I thought it's pretty amazing and would actually like to know how to implement a similar kind of chaining that is capable of somehow deferring the final action until all the functions in the later part of the chain to complete before resolving a result.

Note: The above examples are my simplified version of the actual code for readability sake. The links to their actual files can be seen here and here.


Solution

  • The find() function in mongoose calls the exec() function in the Query object to complete the query and return the result, like in the line of this file.

    Actually no, it doesn't, at least not in your case. See the comment from three lines above:

    // if we don't have a callback, then just return the query object
    

    The .exec() method is only called by find(…, callback) if you pass a callback. When using promises, you don't.

    Instead, the exec method is called by the then() method of the query which makes the query thenable, and which gets used when you await the query object.