以递归方式迭代Promise

时间:2018-03-19 07:45:34

标签: javascript html angular typescript promise

我有一个REST API接口,它只能获得一些信息的第一级。

所以例如我想收集小组。每个小组都可以有子组。例如"第1组"有子组" A组"和" B组"。 " A组"有子组" GroupX"。等等。

但API只为我提供了组名的第一级组。所以我通过"第1组"到API并返回" A组"和" B组"。要获得A组的supgroup,我需要再次调用API。但我不知道它会有多少次迭代。

所以我考虑使用递归,但我还没有走远。

到目前为止我的代码:

getGroupChildren(group:string){ return this restService.getGroupChildren(group)}

getGroups():Promise<any>{
  let collection:string[] = [];
    return this.getGroupChildren("Group A").then((result)=> {
      if(result.data.length !==0){
         return this.getGroupChildren(data[0].groupName);
      }
    });
}

现在这只会让我回到第一个元素的第一个Supgroups。

如何完成它总能找到每个Supgroup,无论多少?使用Observables也许好吗?

这是一个API调用的示例结构:

{  "groupName" : "Group_1",  "children" : ["Group_A", "Group_B"]}

2 个答案:

答案 0 :(得分:3)

您可以使用flatMap

Observable运算符实现您的目标
getGroups(group: string) {

    return this.http.get(`/group/{group}`).flatMap(response => {
        if (response.children.length === 0) { // you hit a leaf, stop recursion here
             return Observable.of(response);
        } else { // there are more levels to go deeper
             return this.getGroups(response.children[0].groupName);
        }
    });
}

修改使用承诺

假设您使用GroupService来返回数据而不是HttpClient。您可以使用Promise运算符将Observable转换为fromPromise

getGroups(group: string) {

    return Observable.fromPromise(this.groupService.get(group)).flatMap(response => {
        if (response.children.length === 0) { // you hit a leaf, stop recursion here
             return Observable.of(response);
        } else { // there are more levels to go deeper
             return this.getGroups(response.children[0].groupName);
        }
    });
}

编辑2 使用此服务

我们来看看你的例子。你有以下json

{
    "groupName": "Group_1", 
    "children" : ["Group_A", "Group_B"]
}

在您的组件文件中,您按如下方式调用服务

...
this.recursiveGroupService.getGroups("Group_1")
    .subscribe(response => {
        // at this point response will be `Group_A`
    })

编辑3 获取整个对象

这一次,我们将使用forkJoin并为所有孩子调用getGroups,并在children数组中收集结果。

注意:我自己没有测试过此代码。它可能包含一些错误。如果有,请告诉我。

import { forkJoin, of } from 'rxjs';
import { map } from 'rxjs/operators';

getGroups(group: string) {
    let retVal;
    return Observable.fromPromise(this.groupService.get(group)).flatMap(response => {
        retVal = {
             groupName: response.groupName
        };
        if (response.children.length === 0) { // you hit a leaf, stop recursion here
             return of(retVal);
        } else { // there are more levels to go deeper
             // this will create list of observable for each child
             const children$ = response.children.map(
                       child => this.getGroups(child)); 
             // forkJoin will execute these observables in parallel
             return forkJoin(children$).pipe(
                  map(results => {
                      // results is an array containing children data
                      retVal.children = results;

                      return retVal;
                  })
             );
         }
    });
}

答案 1 :(得分:1)

您可以使用Promise.all递归解析更深层次的子项,然后使用结果(数组)创建一个对象来解析承诺:

getGroups(groupName = "Group A") {
    return this.getGroupChildren(groupName).then((result) =>
        Promise.all(result.data.map( ({groupName}) => this.getGroups(groupName) ))
    ).then(children => ({ groupName, children }));
}

所以承诺的价值可能是这样的:

[{
    groupName: "Group A",
    children: [{
        groupName: "Group A1",
        children: []
    },  {
        groupName: "Group A2",
        children: []
    }]
}]