7

I have tried a few different ways, basically I want to take out the cloudinary upload code from my routes and put it in a function that my route calls to make the code cleaner. But for some reason I cant get async/await to work/wait for the upload to complete before completing.

Here is an example of my route:

var fieldsUpload = upload.fields([{ name: 'image1', maxCount: 1 }, { name: 'image2', maxCount: 1 }])
router.post('/upload', fieldsUpload, async function (req, res, next) {

   var url1 = await uploadToCloudinary(req.files['image1'][0].path);
   console.log("Cloudinary url: " + url1);
   var url2 = await uploadToCloudinary(req.files['image2'][0].path);
   console.log("Cloudinary url: " + url2);


   res.send("Succesfull Upload"); 

});

And this is my function:

async function uploadToCloudinary(image) {
   try{
      let url = await cloudinary.v2.uploader.upload(image);
   }
   catch(err){ console.log(err)}
}

// function uploadToCloudinary(image) {
//    cloudinary.v2.uploader.upload(image, function(error, result) {
//       if(error) {
//          console.log(error);
//       }
//       else {
//          console.log("Succesfully uploaded image to cloudinary!")
//          return result.secure_url;
//       }
//    });
// }

I put the commented out function I had before so you could see I tried leaving the function not being async and just returning after the callback and have the await in the route but also didnt work. I also dont think I should need to await both in the function and route, but tried like that to see if it worked.

Not sure what I am missing/doing wrong.

Jack
  • 491
  • 7
  • 27
  • Are you sure that cloudinary API methods actually return `Promise`s? If they don't then you obviously can't use `async/await` with them straightforwardly.. – nicholaswmin Dec 19 '18 at 15:06

1 Answers1

16

Because async functions runs with promises and cloudinary SDK functions returns with callbacks, your uploadToCloudinary should look like this :

function uploadToCloudinary(image) {
  return new Promise((resolve, reject) => {
    cloudinary.v2.uploader.upload(image, (err, url) => {
      if (err) return reject(err);
      return resolve(url);
    })
  });
}
Wachaga Mwaura
  • 3,310
  • 3
  • 28
  • 31
dun32
  • 708
  • 6
  • 9
  • Thak you worked perfect!.I would like to ask to learn a little more about await/async and promises, why when I had my function as what is commented out above where I only returned a value inside the callback of uploadToCloudinary function and I had it without async declaration and without the try/catch block, and then inside my route my callback was async and I put an await on the var that received the return of uploadToCloudinary, why didnt that work, since I used a callback for cloudinary and async in my route? Why do I need the promise and resolve reject? And doesnt async replace promises? – Jack Dec 20 '18 at 08:08
  • 1
    all you've described in your comment can be explained with only one fact : async / await works only with promises : [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) – dun32 Dec 20 '18 at 08:19
  • Got it! Thanks dun! – Jack Dec 20 '18 at 14:15
  • Why is the callback fn placed as the second argument? Is that a "typo"? Looking at the docs, it should be the 3rd argument, not the 2nd. Am I missing anything? – ZenVentzi May 09 '19 at 07:06
  • There are example where options are omitted and the callback is in the second parameter, but you're right, if you want to respect API, it should be like `upload(image, {}, (err, url) => {});` – dun32 May 11 '19 at 06:43