【问题标题】:Angular 2 recursive http.gets of unknown depth未知深度的Angular 2递归http.gets
【发布时间】:2018-01-08 04:55:40
【问题描述】:

我一直在使用类似下面的模式将 Angular2 中的 http.gets 链接在一起,以从文件夹的分层结构(两层深)中检索信息(所有伪脚本):

myObservable = this.myService.getSubFolders(topFolderUrl)
    .switchMap(subFolders=> this.myService.getInfoFromSubFolders(subFolders))
    .map(subFolders=> => {
        ...do stuff with subFolders...
        return subFolders;
        }
    );

myService 看起来像这样:

getSubFolders(topFolderUrl): Observable<Folder[]> {
    return this.http.get(topFolderUrl)
        .map(res => {
            let body = res.json();
            let foldersToReturn: Folder[] = [];
            for (let subfolder of body.subFolders) {
                let tempFolder = new Folder;
                tempFolder.url = subfolder.url;
                tempFolder.otherProps = subfolder.otherPropValue;
            }
        return foldersToReturn;
        }
    .catch(this.handleError);
}

getInfoFromSubFolders(subFolders:Folder[]): Observable<Folder[]> {
    let calls: any[]  = [];

    for (let folder of subFolders:Folder){
        calls.push(
            this.http.get(folder.url)
            );

    var subject = new Subject<Folder[]>();       //see: http://stackoverflow.com/a/38668416/2235210 for why Subject

    Observable.forkJoin(calls).subscribe((res: any) => {
        let foundFolder = subFolders.find(folder=> {
                return response.url.indexOf(folder.url)!==-1;
            });
        for (let response of res){
            let bodyAsJson = JSON.parse(response._body);
            foundFolder.otherProps = bodyAsJson.otherPropValue; 
        }
    subject.next(subFolders);
    });
return subject;
}

然后我使用 | 订阅 myObservable我的模板中的异步管道。 myObservable 中的对象最终类似于:

{
  "url": "topFolderUrl", 
  "otherProps": "otherPropsValue", 
  "subFolders": [
    {
      "url": "subFolder1Url",
      "otherProps": "otherPropsValue"
    },
    {
      "url": "subFolder2Url",
      "otherProps": "otherPropsValue",
    }
  ]
}

但是,这依赖于这种文件夹结构恰好是两层深 - 不多也不少,我有两个相关的问题:

  1. 我将如何重构它以允许我以递归方式向下处理一系列文件夹 n 层 - 我一次只能请求一个层 - 即每个子文件夹都有“子文件夹”: [] 等等。
  2. 如果没有子文件夹,我将如何让系统应对?即不在 .switchMap 中调用 getInfoFromSubFolders

我感觉这是一个非常常见的场景,因此它可能对很多人有用。

感谢您的指点

【问题讨论】:

    标签: angular rxjs observable


    【解决方案1】:

    我认为expand 运算符可以帮助您,因为它可以解决此类用例中的递归问题。

    查看这个问题了解更多详情:

    【讨论】:

    • 谢谢@Thierry Templier 看起来好像可以满足我的需要......并且可以处理返回一个空的可观察对象!我稍后会试一试。再次感谢。
    【解决方案2】:

    我在头疼实施时遇到了这篇文章 an other problem to do with recursivity and Observables。幸运的是,我现在可以回答您的问题了。

    要解决的问题 从作为参数提供的文件夹开始,您想访问所有子文件夹。对于每个子文件夹,访问所有子文件夹并重复此过程,没有深度限制。

    为了回答您关于重构和模型的问题,这个问题是一个典型的tree traversal,其中数据结构的选项可用。

    您没有提供有关您的文件夹的详细信息,但让我们做一些假设。您的类具有以下属性:

    • 父级:文件夹
    • 儿童:文件夹[]

    您目前有一个服务,它返回给定文件夹的子文件夹。假设方法签名是:

    myObservable: Observable<Folder[]> = this.myService.getSubFolders(aFolder);
    

    一种使用递归的方法

    为了实现递归方法,它有助于创建一个上下文,该上下文将包含(正在构建的)结果和递归状态所需的任何其他属性:FolderTraversalContext。

    processSubFolders(ctx: FolderTraversalContext): Observable<FolderTraversalContext> {
      return this.getSubFolders(ctx.folder)
        .map( folders: Folder[] => {
          folders.forEach( f => {
            f.parent = folder;
            ctx.toVisit.push(f);
          });
          folder.children = folders; 
    
          //Prepare for next cycle
          ctx.complete = ctx.toVisit.length() === 0;
          if (! ctx.complete) {
            ctx.folder = ctx.toVisit[0];
            ctx.toVisit.splice(0,1);
          }
          return ctx;
        }
    }
    

    扩展运算符的使用

    以反应方式实现递归的方法如下所示:

    readAllSubfolders(topFolder: Folder): Observable<Folder> {
      const ctx = new FolderTraversalContext();
      ctx.topFolder = topFolder;
      ctx.complete = false;
      ctx.toVisit = [];
      ctx.folder = topFolder;
    
      return Observable.of(ctx)
        .expand( ctx => {
          return (ctx.completed) ? Observable.empty() : this.processSubFolders(ctx);
        })
        .map(ctx => ctx.topFolder);
    }
    

    阿莱兹!

    【讨论】:

      猜你喜欢
      • 2021-10-09
      • 2013-11-30
      • 1970-01-01
      • 1970-01-01
      • 2017-02-20
      • 1970-01-01
      • 1970-01-01
      • 2020-01-01
      • 2021-10-28
      相关资源
      最近更新 更多