0

I'm using igmur api to upload images. I wrote an application in Node.js using Promises, async-await. (please do note that I'm fairly new to these concepts).

My code does seem to work. It uploads images to igmur. But, the issue is, the promise does not get resolved. Please refer the code below.

router.post('/images/upload', async (req, res) => {
    /* we would receive a request of file paths as array */
    let filePaths = req.body.urls;

    let multipleUpload = new Promise(async (resolve, reject) => {
            let upload_len = filePaths.length,
                upload_res = new Array();

            for (let i = 0; i <= upload_len + 1; i++) {
                let filePath = filePaths[i];
                await imgur.upload(filePath, (error, result) => {
                    console.log(" A -> ");
                    if (upload_res.length === upload_len) {
                        console.log("******");
                        /* resolve promise after upload is complete */
                        resolve(upload_res)
                    } else if (result) {
                        /*push public_ids in an array */
                        console.log("OK")
                        upload_res.push(result.public_id);
                    } else if (error) {
                        console.log(error)
                        reject(error)
                    }

                })

            }
        })
        .then((result) => console.log(result))
        .catch((error) => error)

    let upload = await multipleUpload;
    res.json({
        'response': upload
    })
})

I followed this tutorial, which does something similar.

dhilt
  • 18,707
  • 8
  • 70
  • 85
CoolCK
  • 416
  • 5
  • 16

3 Answers3

3

I see at least two problems:

  • You mix async with promise when unneeded
  • I suspect imgur.upload does not return a Promise, as it accepts a callback function.

I think this should fix it:

router.post('/images/upload', async (req, res) => {
  let filePaths = req.body.urls
  let upload_len = filePaths.length
  let multipleUpload = filePaths.map(filePath => {
    return new Promise((resolve, reject) => {
      imgur.upload(filePath, (err, result) => {
        if (err) {
          reject(err)
        } else {
          resolve(result.public_id)
        }
      })
    })
  })

  let upload = await Promise.all(multipleUpload)

  res.json({
    response: upload,
  })
})
Anthony Garcia-Labiad
  • 3,531
  • 1
  • 26
  • 30
  • Thanks you very much. code works. as you mentioned, my own function doesn't return a promise :) – CoolCK Oct 14 '18 at 13:33
2

A (very) cleaner and more performant version of your code would be:

function uploadToImgur(filePath) {
    return new Promise((resolve, reject) => {
        imgur.upload(filePath, (err, res) => {
            if (err) reject(err);
            resolve(res.public_id);
        })
    })

}

router.post('/images/upload', async (req, res) => {
    /* we would receive a request of file paths as array */
    let filePaths = req.body.urls;
    let promises = filePaths.map(uploadToImgur);
    let upload = await Promise.all(promises);
    res.json({
        'response': upload
    })
})

This uses Array.map to create an array of promises, one promise corresponding to each filePath, then uses Promise.all to await all the promises concurrently.

Ayush Gupta
  • 8,716
  • 8
  • 59
  • 92
1

Fix your logic to check for length after result is pushed. You are never calling resolve.

For example, if you receive 1 file, you will push into the array, and exit the loop.

if (result) {
  /*push public_ids in an array */
  console.log("OK")
  upload_res.push(result.public_id);

  if (upload_res.length === upload_len) {
    console.log("******");
    /* resolve promise after upload is complete */
    resolve(upload_res)
  }
}

On another topic, you should exit the loop after an error, or you might end up calling reject, then resolve, and that's not good.

Steven Spungin
  • 27,002
  • 5
  • 88
  • 78