Как сделать, чтобы асинхронная функция возвращалась в .map? - PullRequest
1 голос
/ 09 февраля 2020

Я пытаюсь вернуть функцию fetchIDFromPerson и присвоить возвращаемое значение ID до выполнения остальной функции fetchPersons. Он возвращает только неопределенное значение, поскольку он асин c. Что я могу сделать, чтобы заставить его работать? Спасибо.

const fetchIDFromPerson = name => {
  axios
    .get(`https://swapi.co/api/people/?search=${name}&format=json`)
    .then(response => extractImgIDFromURL(response.data.results[0].url))
    .catch(error => console.error(error));
};

let body;

const fetchPersons = (query, imgID) => {
  SWAPIGraphQL.post("", { query })
    .then(result => {
      const { allPersons } = result.data.data;
      return (body = allPersons.map(person => {
        const ID = fetchIDFromPerson(person.name); //This returns undefined!
        return {
          ...person,
          imgID: ID //needs to be assigned a value from fetchIDFromPerson
        };
      }));
    })
    .catch(error => console.error(error));
};

fetchPersons(GET_PERSONS_DATA);

1 Ответ

1 голос
/ 09 февраля 2020

Вам необходимо внести ряд изменений, чтобы правильно использовать обещания, которые возвращает ваш асинхронный код:

  1. return обещание топора ios вызывающей стороне в fetchIDFromPerson().
  2. ошибка повторного выброса в .catch() после регистрации, чтобы вызывающая сторона увидела ошибку
  3. return обещание return SWAPIGraphQL.post() вызывающей стороне в fetchPersons().
  4. Избавьтесь от переменная body. Вы не хотите программировать побочные эффекты, особенно с асинхронным кодом. Сообщите результаты через возвращенные обещания.
  5. Используйте Promise.all() для результатов .map(), чтобы вы знали, когда все эти обещания выполнены.
  6. При вызове fetchPersons() используйте возвращенное обещание чтобы получить разрешенное значение.
  7. Внутри .map() верните обещание от fetchIDFromPerson().
  8. Добавьте .then() туда, куда вы звоните fetchIDFromPerson(), где вы можете вернуть объединенные данные структура с персоной и ID в ней.
  9. Измените response.data.results[0].url на response.results[0].url, чтобы соответствовать структуре данных, которую вы возвращаете.

Вот исправленный код:

const fetchIDFromPerson = name => {
  return axios
    .get(`https://swapi.co/api/people/?search=${name}&format=json`)
    .then(response => extractImgIDFromURL(response.results[0].url))
    .catch(error => {
        // log and rethrow
        console.error(error);
        throw error;
    });
};


const fetchPersons = (query, imgID) => {
  return SWAPIGraphQL.post("", { query })
    .then(result => {
      const { allPersons } = result.data.data;
      return Promise.all(allPersons.map(person => {
        return fetchIDFromPerson(person.name).then(ID => {
            return {
              ...person,
               imgID: ID
            };
        });
      }));
    })
    .catch(error => {
        // log error and rethrow
        console.error(error);
        throw error;
    });
};

fetchPersons(GET_PERSONS_DATA).then(results => {
    console.log(results);
}).catch(err => {
    console.log(err);
});

Вы можете немного упростить fetchPersons(), используя async/await и не регистрируя ошибку как можно больше отдельных мест:

const fetchPersons = async (query, imgID) => {
    const result = await SWAPIGraphQL.post("", { query });
    const { allPersons } = result.data.data;
    return Promise.all(allPersons.map(async (person) => {
        const ID = await fetchIDFromPerson(person.name);
        return {
          ...person,
           imgID: ID
        };
    }));
};
...