简体   繁体   中英

Javascript: Error in Promise implementation

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.

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

}

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM