如何避免嵌套订阅超过两个级别

Posted

技术标签:

【中文标题】如何避免嵌套订阅超过两个级别【英文标题】:how to avoid nested subscribe more than two levels 【发布时间】:2019-09-07 15:53:48 【问题描述】:

我有四个相互依赖的订阅。我知道关于避免嵌套订阅的答案太多了。但是没有人回答超过两个级别。

如何避免这么多的嵌套订阅

这是我的组件代码

if (this.code) 

    this.appService.updateData('Users/clever_token', code: this.code).subscribe(data => 

        if (data.detail) 

            this.accessToken = data.detail.access_token;

            this.appService.getCleverData('/v2.1/me', this.accessToken).subscribe(data1 => 

                if (data1.links) 

                    this.userData.user_type = data1.type;

                    this.appService.getCleverData(data1.links[1].uri, this.accessToken).subscribe(data2 => 

                        if (data2.data) 

                            this.userData.name = data2.data.name.first + ' ' + data2.data.name.last;

                            this.userData.clever_id = data2.data.id;

                            this.userData.email = data2.data.email;

                            this.appService.updateData('Users/cleaver_login', this.userData).subscribe(data3 => 

                                if (data3.detail) 

                                    console.log(data3.detail);
                                
                            );
                        
                    );
                
            );
        
    );

这是服务代码

getCleverData(url, token) 

    let reqHeader = new HttpHeaders(
        'Authorization': 'Bearer ' + token
    )

    return this.http.get(API_PREFIX + url,  headers: reqHeader )
        .pipe(
            map((data: any) => 
                console.log(data);

                if (data) return data;
            ),
            catchError(this.handleError)
        );


/** PUT: update a data to the server */
updateData (url, data?) 

    let httpParams = new HttpParams();
    Object.keys(data).forEach(function (key) 
         httpParams = httpParams.append(key, data[key]);
    );

    return this.http.post(this.apiUrl + url, httpParams, httpOptions)
    .pipe(
        map((data: any) => 
            if (data.status == 0) 
                this.presentToast(data.message);
            

            if (data) return data;
        ),
        catchError(this.handleError)
    );


有什么办法可以避免这么多订阅。我无法删除其中的任何内容,因为其中一些来自我们的服务器,而另一些则是第三方

【问题讨论】:

看看 rxjs 操作符(mergeMap、zip、forkJoin) 看看forkJoin:***.com/questions/43166214/…,这个例子只有2个http请求,但是你可以添加更多的请求。 我试过了。但是有一个只有两个级别的示例,我不能使用 forkJoin,因为所有 API 请求都相互依赖。我不能把他们叫在一起 所以你需要 flatMap:***.com/questions/44593900/…。显然,您必须在发送数据之前更改数据,但至少您没有嵌套的观察者 你不会嵌套订阅,也不是一层 【参考方案1】:

有几个选项,但我认为您需要该结构,因为您需要来自上一个 observable 的数据,因此您可以使用 filter()switchMap()

filter() 能够过滤掉不包含必要值的值switchMap() - 以切换到新流。

更新:

你的代码有一个重构版本:

if (!this.code) 
  return;


this.appService.updateData('Users/clever_token', code: this.code).pipe(
  filter(data => !!data.detail),
  switchMap(data => 
    this.accessToken = data.detail.access_token;

    return this.appService.getCleverData('/v2.1/me', this.accessToken);
  ),
  filter(data1 => !!data1.links),
  switchMap(data1 => 
    this.userData.user_type = data1.type;

    return this.appService.getCleverData(data1.links[1].uri, this.accessToken);
  ),
  filter(data2 => !!data2.data),
  switchMap(data1 => 
    this.userData.name = data2.data.name.first + ' ' + data2.data.name.last;
    this.userData.clever_id = data2.data.id;
    this.userData.email = data2.data.email;

    return this.appService.updateData('Users/cleaver_login', this.userData);
  ),
).subscribe(data3 => 
  if (data3.detail) 
    console.log(data3.detail);
  

【讨论】:

您能创建一个至少 3 个级别的示例,以便我更好地理解它吗?

以上是关于如何避免嵌套订阅超过两个级别的主要内容,如果未能解决你的问题,请参考以下文章

如何将嵌套 div 向上移动两个 div 级别以匹配父级?

ggplot中的嵌套x标签:超过2,同时避免重新排序

角度组件 - 如何避免嵌套组件

Rails 3 - 嵌套资源和多态路径:可以到两个级别,但在三个级别中断

从嵌套字典结构列表(具有两个级别)创建数据框的 Pythonic 方法是啥?

避免在循环中使用嵌套的可观察订阅的正确方法是啥?