【问题标题】:How do I make an asynchronous function return in .map?如何在 .map 中返回异步函数?
【发布时间】:2020-02-10 06:36:11
【问题描述】:

我试图让fetchIDFromPerson 函数返回并将返回的值分配给ID,然后再执行fetchPersons 函数的其余部分。它只返回未定义,因为它是异步的。我该怎么做才能让它工作? 谢谢。

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

【问题讨论】:

  • "它只返回 undefined,因为它是异步的。" - 不,它返回 undefined,因为你忘记了 return 你正在创建的承诺。 (在fetchPersons 中相同,顺便说一句)

标签: javascript asynchronous promise fetch


【解决方案1】:

您需要进行一些更改才能正确使用异步代码返回的承诺:

  1. return axios 对fetchIDFromPerson() 调用者的承诺。
  2. 记录后在.catch() 中重新抛出错误,以便调用者看到错误
  3. return return SWAPIGraphQL.post()fetchPersons() 中的调用者的承诺。
  4. 摆脱body 变量。您不想要副作用编程,尤其是异步代码。通过返回的 Promise 传达结果。
  5. .map() 的结果上使用Promise.all(),这样您就知道所有这些承诺何时完成。
  6. 调用fetchPersons() 时,使用返回的promise 来获取解析值。
  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);
});

您可以通过使用async/await 稍微简化fetchPersons(),而不是将错误记录在许多不同的地方:

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

【讨论】:

  • 检查。检查,检查,检查,检查,检查。也许添加“# drop the catch that only rethrows as it getting logged after Anyway”和“# use async/await to simple” :-)
  • @Bergi - 是的,我正在考虑使用async/await 添加一个简化版本。或许一会儿就能做到。
  • 添加了简化的async/await 实现。
  • @jfriend00 感谢您清理它。我仍然遇到“无法读取未定义的属性'url'”的问题。在fetchIDFromPerson 返回之前,我似乎无法获得该 url 值。
  • @AleksandarZdravkovski - 好吧,如果那来自extractImgIDFromURL(response.data.results[0].url),那么该数据结构或您引用它的方式有问题。您必须自己调试。从console.log(response)console.log(response.data) 开始,然后进一步探索数据结构以了解您的目标。如果这两个看起来正确,则添加console.log(response.data.results),如果看起来正确,则添加console.log(response.data.results[0]),但到那时您可能会看到哪里出了问题。
猜你喜欢
  • 2020-12-08
  • 2021-03-04
  • 1970-01-01
  • 2021-02-23
  • 2023-04-04
  • 2021-07-11
  • 2020-08-19
  • 2020-07-29
  • 1970-01-01
相关资源
最近更新 更多