JQuery asyn c .each возвращает пустые обещания - PullRequest
1 голос
/ 19 февраля 2020

Проблема

Привет друзья,

У меня проблема с тем, что объект promises возвращает меня как пустое []. В то время как console.log, который я задокументировал, показывает мне данные.

Если есть способ решить проблему, я буду признателен.

const getALLMovies = async(page: number = 1): Promise<IMovies[]> =>{
  const res = await axios.get(`${BASE_URL}peliculas/${page}`);
  const body = await res.data;
  const $ = load(body);
  const promises: IMovies[] = [];  

$('body div div div div div div div div div div div div#default-tab-1 div.Posters a').each(async(index , element) =>{
    const $element = $(element);
    const id = $element.attr('href').replace(BASE_URL , '').trim();
    const title = $element.find('div.listing-content p').text().trim();
    const poster = $element.find('img').attr('src');
    const extra = await contentHandler(id);
    promises.push({
      //id: id || null,
      title: title || null,
      poster: poster || null,
      year:   extra[0].year || null,
      genres: extra[0].genres || null,
      rating: extra[0].rating || null,
      synopsis: extra[0].synopsis || null,
      authors:  extra[0].authors || null,
      director: extra[0].director || null,
      writers:  extra[0].writers || null,
      country:  extra[0].country || null,
      releaseDate: extra[0].releaseDate || null,
    })
    //console.log(JSON.stringify(promises , null , 2)) --> The data is shown here.

  });

  return Promise.all(promises);
};

getALLMovies()
  .then(res =>{
    console.log(res.map(x => x)) --> empty object
  })

Ответы [ 2 ]

2 голосов
/ 19 февраля 2020

У вас проблема с состоянием гонки. Ваш обработчик .each планирует некоторый асинхронный код, а именно он должен ожидать результатов contentHandler. Таким образом, когда getALLMovies называется promises, он все еще является пустым массивом, и этот массив не будет заполнен до тех пор, пока не будут завершены все вызовы contentHandler. Т.е. для каждого элемента результат contentHandler ставится в очередь (4 раза в примере ниже).

var promises = [];

function timeout(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function go() {
  $("div").each(async() => {
    await timeout(1500);
    console.log("now");
    promises.push("example");
  })
  console.log(promises);
}

go();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div></div>
<div></div>
<div></div>
<div></div>

Вот как я бы изменил ваш код для достижения желаемого результата:

var promises = [];

function timeout(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function go() {
  console.log("go");

  promises = $("div").map(async () => {
    await timeout(1500);
    console.log ("now");
    return "value"; 
  });

  return Promise.all(promises);
}

go().then(() => console.log(promises.length));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div></div>
<div></div>
<div></div>
<div></div>

Также примечание ... body div div div div div div div div div div div div в вашем селекторе, вероятно, не имеет значения из-за включения #default-tab-1, что является более высоким порядком или специфичностью.

0 голосов
/ 20 февраля 2020

Спасибо @ Zze,

На вашем примере мне удалось показать все данные.

РЕШЕНИЕ

const getALLMovies = async(page: number = 1) =>{
  const res = await axios.get(`${BASE_URL}peliculas/${page}`);
  const body = await res.data;
  const $ = load(body);
  const promises: IMovies[] = [];  

  //const actual = page;
  //const lastPage = parseInt($('body div.app div.layout ul.pagination li').eq(4).find('a').attr('href').match(/\d/g).join("") , 10);
  //const pagination = {
  //  actual: actual,
  //  last: lastPage
  //}

  const promise = $('body div#default-tab-1 div.Posters a').map((index , element) => new Promise(async(resolve) =>{
    const $element = $(element);
    const id = $element.attr('href').replace(BASE_URL, '').trim();
    const title = $element.find('div.listing-content p').text().trim();
    const poster = $element.find('img').attr('src');
    const extra = await contentHandler(id);
    promises.push({
      //id: id || null,
      title: title || null,
      poster: poster || null,
      year: extra[0].year || null,
      genres: extra[0].genres || null,
      rating: extra[0].rating || null,
      synopsis: extra[0].synopsis || null,
      authors: extra[0].authors || null,
      director: extra[0].director || null,
      writers: extra[0].writers || null,
      country: extra[0].country || null,
      releaseDate: extra[0].releaseDate || null,
    });
    resolve(promises)
  }));


  return Promise.all(promise.toArray());
};

getALLMovies()
  .then(res =>{
    console.log(JSON.stringify(res , null , 2))
  })
...