Home > Net >  Execute the next function after the previous asynchronous function is over
Execute the next function after the previous asynchronous function is over

Time:07-10

So guys I am creating a route that Will save a real estate house back to the MongoDB database. I am receiving an array of base 64 images maximum of 10 images. I have an asynchronous function that uploads these images to Cloudinary and therefore for each image, there is an upload response that I push to an array(images) that I will use to create the house back to the database. The Problem I only want to execute the next asynchronous function that creates the house back to the database only after the images array is having all upload responses received from Cloudinary.

If you check my Code I tried using SetTimeOut to execute the next function after 50 seconds but this method sometimes works and sometimes it fails, and this is not something good to send to production. How can I make sure that the house will be created after all images are uploaded to Cloudinary and I have the upload responses in the images array

The Route

Router.post("/createproduct", async (req, res) => {
  const { error } = productValidation.validate(req.body);
  if (error) {
    return res.status(400).json({ message: error.details[0].message });
  }

  try {
    const images = [];
    [...req.body.image].map(async (img) => {
      return new Promise((resolve) => {
        return resolve(
          cloudinary.uploader.upload(img, {
            upload_preset: "fanakaplatinums",
          })
        );
      })
        .then((response) => {
          images.push(response);
        })
        .catch((err) => {
          res.status(400).json({ message: err });
        });
    });
    setTimeout(async () => {
      await productsModel.create({
        name: req.body.name,
        location: req.body.location,
        description: req.body.description,
        price: req.body.price,
        amenities: req.body.amenities,
        image: images,
      });
      console.log("house created successfully");
      res.status(200).json({ message: "house created successfully" });
    }, 50000);
  } catch (error) {
    res.status(500).json({ message: error.message });
  }
});

CodePudding user response:

you can just collect all the promises for line

let cloudinarySavePromises = [...req.body.image].map(async (img) => { ..... }

and apply Promise.all() to wait for all of them.

Check the docs please: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

I assume your code

cloudinary.uploader.upload(img, {
   upload_preset: "fanakaplatinums",
})

returns the promise itself, so you can simplify things a bit

try {
    const images = [];
    const cloudinarySavePromises = [...req.body.image].map((img) => {
        return cloudinary.uploader.upload(img, {
            upload_preset: "fanakaplatinums",
        })
        .then((response) => {
          images.push(response);
        })
        .catch((err) => { /*...*/ })
    });
    await Promise.all(cloudinarySavePromises); // you can add .then .catch here also
    await productsModel.create({ /*...*/ })
    console.log("house created successfully");
    res.status(200).json({ message: "house created successfully" });
} catch (error) {
    res.status(500).json({ message: error.message });
}

Note from the docs:

Promise.all() will reject immediately upon any of the input promises rejecting. In comparison, the promise returned by Promise.allSettled() will wait for all input promises to complete, regardless of whether or not one rejects. Consequently, it will always return the final result of every promise and function from the input iterable.

  • Related