Javascript: ошибка в реализации Promise - PullRequest
0 голосов
/ 25 июня 2019

Я пытаюсь выполнить асинхронную функцию, а затем консоль записать результаты с помощью Promise . Боюсь, я еще не совсем понял концепцию.

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

Я хотел подождать, пока getlink завершит выполнение задач, а затем консоль записать результат.

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

Но он регистрирует результат как пустой даже до того, как getlink завершится.

Ответы [ 2 ]

1 голос
/ 25 июня 2019

Самый простой ответ - это ваше обещание, которое разрешает (return resolve(utlUrls)) до того, как ваш асинхронный код (axios.get(...).then(...)) завершится.

Это минимальный пример для воспроизведения вашей проблемы:

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

Это не работает, потому что мы возвращаем ultUrls до того, как заполним его. Мы не ждем завершения таймаутов.

Чтобы это исправить, просто дождитесь завершения обещаний, используя Promise.all. Дополнительно удалив ненужную упаковку с обещаниями, получим:

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

Кроме того, если вы хотите использовать синтаксис async/await, хотя он и не приносит вам большой выгоды в этом случае, когда у вас есть несколько параллельных запросов, вы можете написать его как:

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));
1 голос
/ 25 июня 2019

Вот как бы я это сделал.Перенос обещаний на массив обещаний.Затем вызывается Promise.resolve, который разрешит все из них в конце.

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

}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...