使用 async/await 和 for 循环进行嵌套 Axios 调用

Jer*_*y M 5 javascript node.js async-await es6-promise axios

我正在使用 Axios 对 Facebook Graph 执行 GET 请求,以获取用户管理的 Facebook 页面列表。完成后,我将使用 afor loop对 Facebook Graph 执行另一个 GET 请求,以提取用户管理的每个 Facebook 页面上的数据。我在 an 内部执行此操作async functionPromise最后将所有数据连接到一个const fbProfile.

我的问题是:const pages我无法从 Axios 调用中获取填充数组的结果pages

我的代码如下:

  async function getfbProfile(token) {
    try {
      const user = await axios.get('https://graph.facebook.com/me', {
        params: {
          access_token: `${token}`,
          fields: 'picture,accounts',
        },
      });
      const pages = await user.data.accounts.data.forEach((err, pageInfo) => {
        axios.get(`https://graph.facebook.com/${user.data.accounts.data[pageInfo].id}`, {
          params: {
            access_token: `${token}`,
            fields: 'picture,name',
          },
        });
      });
      const fbProfile = await Promise.all([user, pages]);
      debug(fbProfile);
    } catch (err) {
      debug(err.stack);
    }
  }
Run Code Online (Sandbox Code Playgroud)

我知道第一个调用会通过,for 循环调用也会通过。我通过修改如下所示来验证for call循环的工作原理,并看到两个调用都成功转到 Facebook Graph。const pages

  const pages = await user.data.accounts.data.forEach((err, pageInfo) => {
    axios.get(`https://graph.facebook.com/${user.data.accounts.data[pageInfo].id}`, {
      params: {
        access_token: `${token}`,
        fields: 'picture,name',
      },
    })
      .then((result) => {
        debug(result);
      });
  });
Run Code Online (Sandbox Code Playgroud)

我将非常感谢任何帮助。这两天我一直在绞尽脑汁地思考这个问题。感谢您提供的任何帮助。

回答

感谢帕特里克·罗伯茨的帮助。由于我使用的是 Airbnb 的 ESLint 配置文件,因此我必须修改下面的示例以通过 linting。再次感谢!

  async function getfbProfile(token) {
    try {
      const user = await axios.get('https://graph.facebook.com/me', {
        params: {
          access_token: token,
          fields: 'picture,accounts',
        },
      });
      const pages = Promise.all(user.data.accounts.data.map(({ id }) => axios.get(`https://graph.facebook.com/${id}`, {
        params: {
          access_token: token,
          fields: 'picture,name',
        },
      })));
      const fbProfile = await Promise.all([user, pages]);
      debug(fbProfile);
    } catch (err) {
      debug(err.stack);
    }
  }
Run Code Online (Sandbox Code Playgroud)

Pat*_*rts 2

Promise.all()不是必需的,user因为它不是一个承诺,因为您已经打开了axios.get()using awaituser.data.accounts.data.map(...)一系列承诺(在你做出我建议的修复之后),所以你也不应该await直接这样做。

这是一个简化的方法:

async function getfbProfile(token) {
  try {
    const user = axios.get('https://graph.facebook.com/me', {
      params: {
        access_token: token,
        fields: 'picture,accounts',
      },
    });
    const pages = Promise.all(user.data.accounts.data.map(({ id }) => {
      return axios.get(`https://graph.facebook.com/${id}`, {
        params: {
          access_token: token,
          fields: 'picture,name',
        },
      });
    }));
    const fbProfile = await Promise.all([user, pages]);
    debug(fbProfile);
  } catch (err) {
    debug(err.stack);
  }
}
Run Code Online (Sandbox Code Playgroud)

这样,user请求pages可以同时发生,而不是顺序发生。await停止控制流,直到承诺得到解决,因此,如果您有不需要按顺序排列的请求,最好使用axios.get()beforeawait一次性创建所有请求(如果可以的话)。