如何在 Angular2 中进行嵌套的 Observable 调用
How to make nested Observable calls in Angular2
我在进行嵌套的 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
});
}
版本 2 - 此代码有效但对我来说似乎是错误的方法:
this.userService.getUser().subscribe(u => {
this.user = u;
this.userService.getPreferences(this.user.username).subscribe(prefs => {
this.preferences = prefs;
});
});
这是模板:
<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-->
我认为显示该服务没有任何意义,它只是进行 http get()
调用,例如:
http.get('http://blablah/users/')
.map((response) => response.json())
请建议定义 Observable 链的最佳工作方法。
你是对的,嵌套订阅是错误的...
平面图正确
这应该有帮助
https://embed.plnkr.co/mqR9jE/preview
或阅读本教程
https://gist.github.com/staltz/868e7e9bc2a7b8c1f754
一些代码...
// responseStream: stream of JSON responses
var responseStream = requestStream
// We use flatMap instead of map to prevent this stream being a metastream - i.e. stream of streams
.flatMap(requestUrl => {
// Convert promise to stream
return Rx.Observable.fromPromise($.getJSON(requestUrl));
}).publish().refCount(); // Make responseStream a hot observable, prevents multiple API requests
// see https://gist.github.com/staltz/868e7e9bc2a7b8c1f754#gistcomment-1255116
这里的请求 URL 是从不同的流/Observable 发出的输入。
现在订阅 responseStream
版本 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
})
.subscribe();
}
您应该稍微阅读一下 rxjs 的运算符。您的示例非常冗长,并且以不应该使用的方式使用 flatMap
和 map
。此外,您的第一个示例无法运行,因为您没有订阅 Observable。
这将满足您的需求:
ngOnInit() {
this.userService.getUser().pipe(
tap(u => this.user = u),
flatMap(u => this.userService.getPreferences(u.username))
).subscribe(p => this.preferences = p);
}
遗产:
在版本 5.5 之前,rxjs 专门使用基于原型的运算符。
此代码在功能上等同于上面的代码:
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);
}
好吧,经过一天的努力和从 Internet 编译信息后,我了解到链接 Observables(按顺序调用 Observables - 一个接一个):
我正在 Angular2 (4) 网站上工作,该网站使用 java 后端 API 来 get/set/modify 数据库中的信息。
我的问题是我必须按 returns 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);
}
);
尽管这段代码是合法且有效的,但我还是需要一个接一个地链接这些 Observable,就像使用 Promises 的异步函数一样。一种方法是将 Observable 转换为 Promises。
另一种方法是使用 RxJS flatMap:
Variant2 -> 另一种方法是使用 flatMap 执行此操作,据我所知,它类似于 Promises then:
this.someService.operation1(someParameters)
.flatMap(u => this.someService.operation2(otherParameters))
.subscribe(function(){
return this.refreshPageMyFunction()
},
function (error) {
console.log(error);
}
);
Variant3 -> 与箭头函数相同:
this.someService.operation1(someParameters)
.flatMap(() => this.someService.operation2(otherParameters))
.subscribe(() => this.refreshPageMyFunction(),
error => console.log(error)
);
return 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);
}
其他资源和有用的评论:
This post approved answer by @j2L4e:
我在进行嵌套的 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
});
}
版本 2 - 此代码有效但对我来说似乎是错误的方法:
this.userService.getUser().subscribe(u => {
this.user = u;
this.userService.getPreferences(this.user.username).subscribe(prefs => {
this.preferences = prefs;
});
});
这是模板:
<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-->
我认为显示该服务没有任何意义,它只是进行 http get()
调用,例如:
http.get('http://blablah/users/')
.map((response) => response.json())
请建议定义 Observable 链的最佳工作方法。
你是对的,嵌套订阅是错误的...
平面图正确
这应该有帮助
https://embed.plnkr.co/mqR9jE/preview
或阅读本教程
https://gist.github.com/staltz/868e7e9bc2a7b8c1f754
一些代码...
// responseStream: stream of JSON responses
var responseStream = requestStream
// We use flatMap instead of map to prevent this stream being a metastream - i.e. stream of streams
.flatMap(requestUrl => {
// Convert promise to stream
return Rx.Observable.fromPromise($.getJSON(requestUrl));
}).publish().refCount(); // Make responseStream a hot observable, prevents multiple API requests
// see https://gist.github.com/staltz/868e7e9bc2a7b8c1f754#gistcomment-1255116
这里的请求 URL 是从不同的流/Observable 发出的输入。
现在订阅 responseStream
版本 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
})
.subscribe();
}
您应该稍微阅读一下 rxjs 的运算符。您的示例非常冗长,并且以不应该使用的方式使用 flatMap
和 map
。此外,您的第一个示例无法运行,因为您没有订阅 Observable。
这将满足您的需求:
ngOnInit() {
this.userService.getUser().pipe(
tap(u => this.user = u),
flatMap(u => this.userService.getPreferences(u.username))
).subscribe(p => this.preferences = p);
}
遗产:
在版本 5.5 之前,rxjs 专门使用基于原型的运算符。 此代码在功能上等同于上面的代码:
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);
}
好吧,经过一天的努力和从 Internet 编译信息后,我了解到链接 Observables(按顺序调用 Observables - 一个接一个):
我正在 Angular2 (4) 网站上工作,该网站使用 java 后端 API 来 get/set/modify 数据库中的信息。
我的问题是我必须按 returns 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);
}
);
尽管这段代码是合法且有效的,但我还是需要一个接一个地链接这些 Observable,就像使用 Promises 的异步函数一样。一种方法是将 Observable 转换为 Promises。
另一种方法是使用 RxJS flatMap:
Variant2 -> 另一种方法是使用 flatMap 执行此操作,据我所知,它类似于 Promises then:
this.someService.operation1(someParameters)
.flatMap(u => this.someService.operation2(otherParameters))
.subscribe(function(){
return this.refreshPageMyFunction()
},
function (error) {
console.log(error);
}
);
Variant3 -> 与箭头函数相同:
this.someService.operation1(someParameters)
.flatMap(() => this.someService.operation2(otherParameters))
.subscribe(() => this.refreshPageMyFunction(),
error => console.log(error)
);
return 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);
}
其他资源和有用的评论:
This post approved answer by @j2L4e: