Where does this express js callback come from?

Hi all,

after some freecodecamp I started doing the Express js tutorial from MDN (https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Home_page) for some backend.

I am stuck at understanding where the callback in the async.parallel is coming from and what is represents.

If I delete the callback the site wont load, so it must have some important meaning but unfortunately I have no glue. Is it calling the function(err, results) { res.render(‘index’, […] }) to make the result availalble for data?

var Book = require(’…/models/book’);

var async = require(‘async’);

exports.index = function(req, res) {

async.parallel({
    book_count: function(**callback**) {
        Book.countDocuments({}, **callback**);
    },
    book_instance_count: function(**callback**) {
        BookInstance.countDocuments({}, **callback**);
    },
    book_instance_available_count: function(**callback**) {
        BookInstance.countDocuments({status:'Available'}, **callback**);
    },
    author_count: function(**callback**) {
        Author.countDocuments({}, **callback**);
    },
    genre_count: function(**callback**) {
        Genre.countDocuments({}, **callback**);
    }
}, function(err, results) {
    res.render('index', { title: 'Local Library Home', error: err, data: results });
});

};

In express simplest route handler looks like this:

app.get('/', function(req, res) {
  res.send('Hello world!');
});

When user goes to the homepage ('/'), express sends back response (res.send) which contains text Hello world! which finishes request.
res.render() is another option to finish request - here it creates html page from a partial file (index) and some variables (title and error).
So every time you have a request you need to finish it with response (res.send(), res.render() etc.) or either express will hang.

According to async documentation async.parallel accepts tasks as the first parameter and an optional callback that gets called either when all the tasks are finished or one of the tasks errors. Therefore by calling the callback we are making sure that the request will be finished and express will render and return a webpage (either with data or with an error message).

Look at what happens inside of each function - database queries. Database queries, say, in Mongoose have their own callback structure. And, when thinking about those callbacks, you have to know what the query will return if successful. You might get an array of documents, or a cursor that points to an array of documents. Or, you might just get a single document.

From the Mongoose Docs:

All callbacks in Mongoose use the pattern: callback(error, result) . If an error occurs executing the query, the error parameter will contain an error document, and result will be null. If the query is successful, the error parameter will be null, and the result will be populated with the results of the query.

Anywhere a callback is passed to a query in Mongoose, the callback follows the pattern callback(error, results) . What results is depends on the operation: For findOne() it is a potentially-null single document, find() a list of documents, count() the number of documents, update() the number of documents affected, etc. The API docs for Models provide more detail on what is passed to the callbacks.

https://mongoosejs.com/docs/queries.html

Start there on the inside of each function and work your way out, thinking about what should be returned and how the data should be handled.

Or, were you just asking about the final callback? In that case, it’s stated in the documentation at the end of the ‘Controller’ section:

The async.parallel() method is passed an object with functions for getting the counts for each of our models. These functions are all started at the same time. When all of them have completed the final callback is invoked with the counts in the results parameter (or an error).

On success the callback function calls res.render() , specifying a view (template) named ’ index ’ and an object containing the data that is to be inserted into it (this includes the results object that contains our model counts). The data is supplied as key-value pairs, and can be accessed in the template using the key.