递归调用异步 API 调用

Posted

技术标签:

【中文标题】递归调用异步 API 调用【英文标题】:Recursively calling an asynchronous API call 【发布时间】:2018-01-30 12:27:42 【问题描述】:

我正在尝试从每次调用仅返回 1000 个项目的 API 获取数据,并且我想递归地执行此操作,直到获得所有数据。

我不知道总共有多少项目,所以每次打电话后我都要检查一下

如果调用是同步的,我会使用这样的:

function fetch(all, start) 
    const newData = getData(start, 1000);
    all = all.concat(newData);
    return (newData.length === 1000) ? fetch(all, all.length) : all;

但是,这里的getData() 调用是异步的。使用Promise.all() 不起作用,因为我事先不知道需要多少调用,所以我无法准备调用数组。

我觉得我可以用生成器或async/await 解决这个问题,但我不知道怎么做。谁能指出我正确的方向?

以防万一,我使用的是 Angular 4。

【问题讨论】:

【参考方案1】:

您可以使用async/await 实现此功能,无需递归:

let fetch = async () 
  try 
    let start = 0;
    let all = [];
    let newData;
    do 
      newData = await getData(start, 1000);
      start += newData.length;
      all = all.concat(newData);
     while (newData.length > 0);

    return all;
   catch (err) 
    console.log(err);
  

【讨论】:

你的解决方案和@estus 的一样好用,但他的只是更干净一点。不过感谢您的回答,我没有意识到这会如此简单。 小心递归函数,如何处理异步函数getData中抛出的错误也是个问题。 谢谢,我会记住的。我倾向于递归,因为它使代码更具功能性(更少的状态变量),但我同意它确实带来了处理错误的挑战。【参考方案2】:

这取决于您的情况如何完成。考虑到 getData 返回一个承诺,它是:

async function fetch(all, start) 
    const newData = await getData(start, 1000);
    all = all.concat(newData);
    return (newData.length === 1000) ? await fetch(all, all.length) : all;

【讨论】:

太棒了,就这么简单。谢谢! 不客气。是的,这就是 async/await 很棒的原因。

以上是关于递归调用异步 API 调用的主要内容,如果未能解决你的问题,请参考以下文章

Discord.js - 尝试等待异步进程并允许递归调用包装器

根本原因:对自动化对等 API 的递归调用无效

节点递归承诺永远不会退出

如何使用 Promise Kit 调用递归函数?

如何在Lua中使用递归函数来动态构建表而不会在每次调用时覆盖它

JS递归的常见用法