使用 promises 递归检索分页数据

3
我正在使用一个返回分页数据的函数。它最多返回100个项目和一个用于检索下一个100个项目的键。我想检索所有可用的项目。
我该如何递归实现这一点?在这里使用递归是一个好选择吗?我能否不使用递归以其他方式完成?
我正在使用 Bluebird 3x 作为 promises 库。
以下是我尝试实现的代码片段:
getEndpoints(null, platformApplication)
  .then(function(allEndpoints) {
    // process on allEndpoints
  });


function getEndpoints(nextToken, platformApplication) {
  var params = {
    PlatformApplicationArn: platformApplication
  };

  if (nextToken) {
    params.NextToken = nextToken;
  }

  return sns.listEndpointsByPlatformApplicationAsync(params)
    .then(function(data) {
      if (data.NextToken) {
        // There is more data available that I want to retrieve.
        // But the problem here is that getEndpoints return a promise
        // and not the array. How do I chain this here so that 
        // in the end I get an array of all the endpoints concatenated.
        var moreEndpoints = getEndpoints(data.NextToken, platformApplication);
        moreEndpoints.push.apply(data.Endpoints, moreEndpoints);
      }

      return data.Endpoints;
    });
}

但问题在于,如果有更多的数据需要检索(参见 if (data.NextToken) { ... }),我该如何将这些 promise 链接起来,以便最终获得所有端点列表等。


你想什么时候获取下一个100?是什么触发了它? - Tad Donaghe
当有更多的数据可用时,如果data.NextToken可用,则意味着有更多的数据可用,因此我必须获取它。 - Shikasta_Kashti
所以你想要获取所有的端点? - CrimsonChris
是的。抱歉在问题中没有表述清楚,已经更新了。 - Shikasta_Kashti
2个回答

5

递归可能是获取所有端点的最简单方法。

function getAllEndpoints(platformApplication) {
    return getEndpoints(null, platformApplication);
}

function getEndpoints(nextToken, platformApplication, endpoints = []) {
  var params = {
    PlatformApplicationArn: platformApplication
  };

  if (nextToken) {
    params.NextToken = nextToken;
  }

  return sns.listEndpointsByPlatformApplicationAsync(params)
    .then(function(data) {
      endpoints.push.apply(endpoints, data.Endpoints);
      if (data.NextToken) {
          return getEndpoints(data.NextToken, platformApplication, endpoints);
      } else {
          return endpoints;
      }
    });
}

我知道了。默认参数endpoints = []是ES5还是ES6功能?它能在Node.js版本0.10.36下工作吗? - Shikasta_Kashti
1
如果您无法访问默认参数(ES6),则只需从getAllEndpoints传入一个空数组,或在getEndpoints中手动检查未定义。 - CrimsonChris
顺便问一下,push应该像这样:endpoints.push.apply(endpoints, data.Endpoints);,因为我们返回的是endpoints而不是data.Endpoints。只是想确认一下... - Shikasta_Kashti
1
是的,我从问题中复制了它。已经修复了。 - CrimsonChris
哦,抱歉。我不知道push.apply的工作原理,所以我弄错了,但现在我查看了文档并修复了它。谢谢你的帮助,非常感激。它现在完美地运行。 - Shikasta_Kashti

0

以下是我想出来的一个更通用的例子,用于递归地获取和返回分页终端的数据:

getData(page, dataArray) {
  return new Promise((resolve, reject) => {
    getEndpointHere(
      {         
        page,
        pageSize: 50,
      },     
      (err, result) => {
        if (err)
          return console.error("there was a problem retrieving your data");          

        dataArray = dataArray.concat(result);

        if (result.length < 50) {
          resolve(dataArray);
        } else {
          resolve(getData(page + 1, dataArray));
        }
      }
    );
  });
}

getData(1, [])
.then((res) => {      
  console.log("SEVERAL PAGES OF DATA", res);
})

这个例子使用了回调函数 -- (err, result) -- 但是,这个逻辑可以被提取出来处理来自端点的响应。我正在使用的资源没有返回游标或“下一个”令牌,指示是否有更多记录,因此我使用如果响应少于50条记录作为继续请求更多数据的基础的逻辑。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接