0

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.

4
  • review the promise documentation here. you should call resolve when the async operation is completed. This should be inside the .then from axios. you shouldn't be returning the result of resolve, you just call it. the example in the documentation is very clear, just implement your code based on that. Commented Jun 25, 2019 at 15:22
  • 1
    In addition, if you will be doing multiple async tasks, a common technique is to push the promises that each async task returns into an array, and use the Promise.all() or Promise.allSettled() methods on that promise array to wait for them all to finish (or in the case of Promise.all, either for them all to finish, or for the first one to reject) before taking action. All described in the docs Chris linked. Commented Jun 25, 2019 at 15:25
  • I will definitely check the docks. your suggestion to put resolve in axios ,but I'm performing axios call multiple times though. Commented Jun 25, 2019 at 15:27
  • @thmsdnnr got it. I'll try it Commented Jun 25, 2019 at 15:28

2 Answers 2

1

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));

Sign up to request clarification or add additional context in comments.

Comments

1

This is how I would do it. Pushing the promises onto a promise array. THen calling Promise.resolve which will resolve all of them at the end.

  async function getLinks(param, data) {
let psub;
var name;
let g;
let promises = [];
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;
        // I would break this out into it's own function probabaly
        promises.push(
        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 Promise.all(promises)
  .then((yourData) => {
    return yourData;
  });

}

1 Comment

Sorry, I removed the resolve() you don't need that part. Just return it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.