Javascript: Error in Promise implementation

Tags: , ,



I’m trying to perform async function and then console log the results with the help of Promise. I’m afraid I haven’t quite grasped the concept yet.

getlinks performs async action.

async function getLinks(param, data) {
  return new Promise((resolve, reject) => {
    let psub;
    var name;
    let g;

    psub = checkForPsub(param);
    var ultUrls = [];

    _.each(data, o => {
      title = sanitizeString(o.title);
      if (psub == true) {
        name = title + " u -- " + o.author;
      } else {
        name = title;
      }

      switch (o.domain) {
        case "i.imgur.com":
          {
            // downloadImgur(o,name)
          }
          break;
        case "imgur.com":
          {
            id = o.url.substring(o.url.lastIndexOf("/") + 1);
            if (
              o.url.includes("https://imgur.com/a/") ||
              o.url.includes("https://imgur.com/gallery/") ||
              o.url.includes("http://imgur.com/a/") ||
              o.url.includes("http://imgur.com/gallery/")
            ) {
              let urls = [];
              let file_name;
              axios
                .get(
                  "https://api.imgur.com/3/album/" + id,

                  { headers: { Authorization: "Client-ID 295ebd07bdc0ae8" } }
                )
                .then(res => {
                  let images = res.data.data.images;

                  _.each(images, function(v) {
                    var ext = v.link.split(".").pop();
                    if (ext == "gifv") {
                      ext = "mp4";
                    }
                    if (psub == true) {
                      file_name =
                        title + "--" + v.id + " " + "u--" + auth + "." + ext;
                    } else {
                      file_name = title + "--" + v.id + "." + ext;
                    }

                    let p = { url: v.link, file_name: file_name };
                    ultUrls.push(p);
                  });
                })
                .catch(err => {
                  console.log(err);
                });
            }
          }
          break;
        case "i.redd.it":
          {
          }
          break;
        default:
          console.log("other", o.domain);
      }
    }); //end each

    return resolve(ultUrls);
  });
}

I wanted to wait till getlinks finished performing tasks and then console log the result.

 getLinks(sub,result).then(res =>  console.log({res}))

But the it logs the result as empty even before the getlink is finished.

Answer

The simplest answer is you’re promise is resolving (return resolve(utlUrls)) before your async code (axios.get(...).then(...)) completes.

This is a minimal example to reproduce your problem:

let timeout = ms => new Promise(resolve => setTimeout(() => resolve(ms), ms));

async function getLinks(urls) {
  return new Promise((resolve, reject) => {
    let ultUrls = [];
    urls.forEach(url =>
        timeout(500).then(res => ultUrls.push(res)))
    return resolve(ultUrls);
  });
}

getLinks([1, 2, 3]).then(a => console.log(a));

It doesn’t work because we return ultUrls before we’ve filled it. We don’t wait for the timeouts to complete.

To fix this, simply wait for the promises to complete using Promise.all. Additionally removing some unnecessary wrapping of promises, we get:

let timeout = ms => new Promise(resolve => setTimeout(() => resolve(ms), ms));

function getLinks(urls) {
  let ultUrls = [];
  let promises = urls.map(url =>
      timeout(500).then(res => ultUrls.push(res)))
  return Promise.all(promises).then(a => ultUrls);
}

getLinks([1, 2, 3]).then(a => console.log(a));

Furthermore, if you want to use the async/await syntax, though it doesn’t buy you much in this case where you have multiple requests in parallel, you could write it as:

let timeout = ms => new Promise(resolve => setTimeout(() => resolve(ms), ms));

async function getLinks(urls) {
  let ultUrls = [];
  let promises = urls.map(url =>
      timeout(500).then(res => ultUrls.push(res)))
  await Promise.all(promises);
  return ultUrls;
}

getLinks([1, 2, 3]).then(a => console.log(a));


Source: stackoverflow