Home > Software engineering >  Unexpected asynchronicity in NodeJS
Unexpected asynchronicity in NodeJS

Time:12-05

I'm trying to search for all activities however the code appears to return an empty array of activities before it finishes searching all Course model instances with unexpected asynchronicity in the code.

const express = require("express");
const router = express.Router();

const Activity = require("../../models/Activity");
const Course = require("../../models/Course");

router.get("/:user_id", (req, res) => {
  Course.find({ subscribers: req.params.user_id })
    .then((courseList) => {
      let activities = [];
      courseList.forEach((course) =>
        Activity.find({ courseId: course._id }).then((activity) => {
          activities = [...activities, ...activity];
        })
      );

      return res.json({ activities });
    })
    .catch((err) => res.status(404).json({ nocoursefound: "No Course found" }));
});

module.exports = router;

when I change the return line to return setTimeout(() => res.json({ activities }),500) I get the list of activities I'm searching for. I want to remove the setTimeout function and to successfully retrieve the activities list.

CodePudding user response:

Looks like the issue is that the Course.find method is asynchronous, meaning that it returns immediately without waiting for the search to complete. This means that the res.json method is called before the activity array has been populated with the results of the search.

One way to fix this issue would be to use the Promise.all method, which allows you to wait for multiple promises to complete before continuing with the rest of the code. You can use this method to wait for all of the Activity.find promises to complete before calling res.json.

Here's an example of how you could modify your code to use Promise.all:

router.get("/:user_id", (req, res) => {
  Course.find({ subscribers: req.params.user_id })
    .then((courseList) => {
      let activityPromises = [];
      courseList.forEach((course) => {
        activityPromises.push(Activity.find({ courseId: course._id }));
      });

      return Promise.all(activityPromises);
    })
    .then((activityLists) => {
      // Flatten the array of arrays into a single array
      let activities = [].concat.apply([], activityLists);
      return res.json({ activities });
    })
    .catch((err) => res.status(404).json({ nocoursefound: "No Course found" }));
});

This code uses the Promise.all method to wait for all of the Activity.find promises to complete before calling res.json.

  • Related