【问题标题】: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:stackoverflow.com/questions/43166214/…,这个例子只有2个http请求,但是你可以添加更多的请求。
  • 我试过了。但是有一个只有两个级别的示例,我不能使用 forkJoin,因为所有 API 请求都相互依赖。我不能把他们叫在一起
  • 所以你需要 flatMap:stackoverflow.com/questions/44593900/…。显然,您必须在发送数据之前更改数据,但至少您没有嵌套的观察者
  • 你不会嵌套订阅,也不是一层

标签: javascript angular


【解决方案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 个级别的示例,以便我更好地理解它吗?
猜你喜欢
  • 2023-01-30
  • 2020-08-18
  • 2019-10-03
  • 2018-11-27
  • 2023-01-11
  • 2020-05-31
  • 2022-08-25
  • 1970-01-01
  • 2022-06-22
相关资源
最近更新 更多