如何在Angular2中进行嵌套的Observable调用

nuv*_*vio 25 rxjs angular2-observables angular

我在制作嵌套的Observable调用时遇到了一些麻烦.我的意思是调用一个http服务来检索用户,然后从用户获取id以进行另一个http调用,最后在屏幕上呈现结果.

1)HTTP GET 1:获取用户

2)HTTP GET 2:获取用户的首选项,将唯一标识符作为参数传递

这转换为组件中的以下代码Blah.ts:

版本1 - 此代码不显示任何内容

 ngOnInit() {
        this.userService.getUser()
            .flatMap(u => {
                this.user = u; // save the user
                return Observable.of(u); // pass on the Observable
            })
            .flatMap(u => this.userService.getPreferences(this.user.username)) // get the preferences for this user
            .map(p => {
                this.preferences = p; // save the preferences
            });
    }
Run Code Online (Sandbox Code Playgroud)

版本2 - 此代码有效,但对我来说似乎是错误的方法:

 this.userService.getUser().subscribe(u => {
            this.user = u;
            this.userService.getPreferences(this.user.username).subscribe(prefs => {
                this.preferences = prefs;
            });
        });
Run Code Online (Sandbox Code Playgroud)

这是模板:

<h3>User</h3>

<div class="row col-md-12">
    <div class="col-md-6">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title">User details</h3>
            </div>
            <div class="panel-body">
                <table class="table table-condensed">
                    <thead>
                        <tr>
                            <th>Username</th>
                            <th>Full Name</th>
                            <th>Enabled</th>                                
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>{{user?.username}}</td>
                            <td>{{user?.fullName}}</td>
                            <td>{{user?.enabled}}</td>                          
                        </tr>
                    </tbody>
                </table>
            </div>
        </div>
    </div>
    <!-- end of col 1-->

    <div class="col-md-6">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title">User preferences</h3>
            </div>
            <div class="panel-body">
                <table class="table table-condensed">
                    <thead>
                        <tr>
                            <th>Language</th>
                            <th>Locale</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>{{preferences?.preferences?.get('language')}}</td>
                            <td>{{preferences?.preferences?.get('locale')}}</td>
                        </tr>
                    </tbody>
                </table>
            </div>
        </div>
    </div>
    <!-- end of col 2-->

</div>
<!-- end of row 1-->
Run Code Online (Sandbox Code Playgroud)

我不认为展示服务有任何意义,只需http get()拨打电话:

  http.get('http://blablah/users/')
        .map((response) => response.json())
Run Code Online (Sandbox Code Playgroud)

请建议哪个是定义Observable链的最佳工作方法.

j2L*_*L4e 34

你应该读一下rxjs的运算符.您的示例非常详细和使用,flatMap并且map在某种程度上它们不应该被使用.你的第一个例子也行不通,因为你没有订阅Observable.

这将满足您的需求:

ngOnInit() {
    this.userService.getUser()
        .do(u => this.user = u) //.do just invokes the function. does not manipulate the stream, return value is ignored.
        .flatMap(u => this.userService.getPreferences(u.username))
        .subscribe(p => this.preferences = p);
}
Run Code Online (Sandbox Code Playgroud)

从rxjs 5.5开始,您应该使用可管道运算符:

ngOnInit() {
    this.userService.getUser().pipe(
        tap(u => this.user = u),
        flatMap(u => this.userService.getPreferences(u.username))
      ).subscribe(p => this.preferences = p);
}
Run Code Online (Sandbox Code Playgroud)

  • 任何错误都会一直传递到管道上 (3认同)
  • +1-使用此解决方案,我只有一个问题,处理两个服务调用均可能引发的错误的最佳方法是什么?我了解您可以在subscription方法中添加错误处理程序;但是,这仅适用于getPreferences服务调用。捕获两次呼叫中的错误的最干净方法是什么?假定它们都应以相同的方式处理。谢谢 (2认同)

Com*_*ine 8

好吧,所以经过一天的互联网挣扎和编译信息后,我学到了关于链接Observables(按序列调用Observables - 一个接一个)的知识:

我正在开发一个Angular2(4)网站,该网站使用java后端API来获取/设置/修改数据库中的信息.

我的问题是我必须在返回Observables(RxJS)的序列中进行两次API(HTTP POST)调用.

我有Operation1和Operation2.操作2应在操作1完成后执行. 在此输入图像描述

Variant1 - >起初我在其他内部做了一个(比如javascript中的嵌套函数):

     this.someService.operation1(someParameters).subscribe(
        resFromOp1 => {
          this.someService.operation2(otherParameters).subscribe(
            resFromOp2 => {
              // After the two operations are done with success
              this.refreshPageMyFunction() 
            },
            errFromOp2 => {
              console.log(errFromOp2);
            }
          );
        },
        errFromOp1 => {
          console.log(errFromOp1);
        }
      );
Run Code Online (Sandbox Code Playgroud)

尽管这些代码是合法且有效的,但我还是要求一个接一个地链接这些Observable,就像使用Promise的异步函数一样.一种方法是将Observables转换为Promises.

另一种方法是使用RxJS flatMap:

Variant2 - >另一种方法是用flatMap做这个,据我所知,它类似于Promises:

   this.someService.operation1(someParameters)
    .flatMap(u => this.someService.operation2(otherParameters))
    .subscribe(function(){
        return this.refreshPageMyFunction()
      },
      function (error) {
        console.log(error);
      }
    );
Run Code Online (Sandbox Code Playgroud)

Variant3 - >与Arrow功能相同:

   this.someService.operation1(someParameters)
    .flatMap(() => this.someService.operation2(otherParameters))
    .subscribe(() => this.refreshPageMyFunction(),
      error => console.log(error)
    );
Run Code Online (Sandbox Code Playgroud)

返回Observables的方法基本上是:

  operation1(someParameters): Observable<any> {
    return this.http.post('api/foo/bar', someParameters);
  }

  operation2(otherParameters): Observable<any> {
    return this.http.post('api/some/thing', otherParameters);
  }
Run Code Online (Sandbox Code Playgroud)

其他资源和有用的评论:

This post approved answer by @j2L4e: https://stackoverflow.com/a/40803745/2979938

https://stackoverflow.com/a/34523396/2979938

https://stackoverflow.com/a/37777382/2979938
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢这个回复,但是,大多数异步链案例都涉及将参数从operation1传递给operation2,您是否可以将它添加到您的示例而不是otherParameters?我完全理解你的例子,但这会使他们完整. (3认同)