使用 Promise 使用 axios 获取分页响应

问题描述 投票:0回答:2

我正在尝试弄清楚如何使用

Promise
async
/
 await
从 Rest API 获取数据,该 API 返回带有一些分页逻辑的数据。

具体来说,我正在尝试使用 MS Graph API 获取 Azure 用户数据。由于 azure 不会在单个 API 中发送与用户相关的所有数据,因此我们必须进行多次调用来为单个 Azure 用户构建数据。

为了深入了解我的代码/逻辑,以下是我如何使用分页逻辑获取用户的基本数据:

let nextPageLink: string| null = null;
do {
      let pagedResult: AggregationPageResult = await this.fetchNextPage(nextPageLink);
      let usersMap: Map<string, any>[] = pagedResult.data!;
      nextPageLink = pagedResult.nextPageLink!;
      this.sendPageResult(usersMap, res);
} while(nextPageLink) 

这里的分页逻辑很简单,并且不会打扰我。假设第一次调用 Users Graph API 返回 100 个用户。现在,对于这 100 个用户中的每一个,我都必须单独调用以获取他们的组成员数据、目录角色数据、上次登录活动和其他“N”个详细信息。

这是我用来获取当前页面中每个用户的组成员详细信息的代码:

for(let user of usersToSearch) {
    let groupMembershipAPI = "https://graph.microsoft.com/v1.0/users/" + user + "/memberOf/microsoft.graph.group";
    
     let httpConfig: HttpRequestConfig = {
             baseURL: groupMembershipAPI, 
             method: 'GET',
             queryFilter: filters
         }
    
      executions.push(httpClient.executeRequest(httpConfig, true));
}    

let executionResults: HttpResponse [] = await Promise.all(executions);

现在此代码可以正常工作并获取所有用户的组成员详细信息,iff成员身份较少,或者换句话说,成员身份数据适合默认页面大小或任何页面大小。如果数据更多,如果任何特定用户有 1000 个组成员资格并且默认页面大小只有 100,该怎么办。在这种情况下,我当前的逻辑只会带来 100 个成员资格,因为我不会在下一页执行它

对于我推送的所有请求

executions
,我还想注意 API 是否发送有效的 nextPageLink,以便代码再次获取该用户的会员数据,直到 nextPageLink 为空。

现在这只是组成员资格的一种场景,考虑一下如果我想携带所有其他数据(如目录角色、PIM 数据、上次登录活动等)会发生什么!

用于带来用户页面的原始分页逻辑也可以在这里使用,但我正在寻找一种解决方案,可以递归或动态添加 Promise 链,或者是否有任何其他机制可以帮助我以更好的方式解决它?我还想确保性能和资源利用率


编辑1:我打算在获取用户属性(例如其组成员身份/角色等)时使用不同的分页方法是因为:

  1. 我想顺序同步处理用户页面
  2. 相反,在获取这些属性时,它们可以并行运行。
  3. 意思是,我想要实现的是,获取用户组成员身份属性可以与获取用户角色并行运行......
  4. 我不想等待开始角色获取,因为用户组获取正在进行中。两者可以并行运行
  5. 如果我使用原来的方法,那么这将是连续的。

用伪代码来解释我的上述观点:

 async public fetchNextPage(nextPageLink: string): AggregationPageResult {
    let propertyFetchResults = []
     1. await fetch the next user page
     2. for every extra property to be fetched with pagination
          2.a propertyFetchResults.push (...result)
     3. await Promise.all(propertyFetchResults)
     4. merge the above property results with users of current page
    
 }
javascript typescript async-await axios es6-promise
2个回答
0
投票

您可以尝试编写一个通用提取,只要有更多页面并聚合数据,它就会继续提取,如下所示: (这显然应该根据预期的响应结构进行修改)

async function fetchAllPages(url) {
    let aggregator = [];
    const response = await fetch(url);
    const results = await response.json();
    aggregator = results.data;
    
    if(results.nextLink){
        aggregator.concat(await fetchAllPages(results.nextLink))
    }
    return aggregator;
}


0
投票
  1. 首先您需要了解您是否真的需要使用 do/while 获取所有页面?在大多数情况下,仅当用户滚动到底部或单击下一页时,您才需要获取下一页。

  2. 如果可能的话,首先聚合ID(例如获取页面上所有用户的所有组ID),将它们放入Set以删除重复项,然后获取。使用接受数组而不是一个 id 的 API,例如 getGroups(ids) 而不是多个 getGroup(id):

const users = fetch(...)

const promises = []

// fetch groups
const groupIds = Array.from(new Set(users.map(x => x.groupId)))
while (groupIds.length) {
  promises.push(fetchGroups(groupIds.splice(0, 100))) // If 100 is a limit for this API
}

// fetch roles
const roleIds = Array.from(new Set(users.map(x => x.roleId)))
while (roleIds) {
  promises.push(fetchRoles(roleIds(0, 100))) // If 100 is a limit for this API
}

...

await Promise.all(promises)
  1. 记住错误处理。如果一个请求失败怎么办?您想使用 AbortController 取消所有其他请求,还是重试几次失败的请求,或者忽略等等?

  2. 记住缓存 - 您的缓存中可能已经有一些实体,如果它们足够新鲜,您可以跳过再次获取它们。

  3. Axios 不是必须有的库,大多数开发人员甚至无法解释他们为什么使用它。

© www.soinside.com 2019 - 2024. All rights reserved.