我有这个功能:
/**
* Attempt login with provided credentials
* @returns {Observable<number>} the status code of HTTP response
*/
login(username: string, password: string): Observable<number> {
let body = new URLSearchParams();
body.append('grant_type', 'password');
body.append('username', username);
body.append('password', password);
return this.http.post(Constants.LOGIN_URL, body, null)
.do(res => {
if (res.status == 200) {
this.authTokenService.setAuthToken(res.json().auth_token);
}
})
.map(res => res.status)
.catch(err => { return Observable.throw(err.status) });
}
此函数尝试执行登录并返回调用方可以使用的Observable<number>
,以便收到响应的 HTTP 代码通知。
这似乎有效,但我有一个问题:如果调用方只是调用函数而不订阅返回的Observable
,则不会调用do
函数并且不会保存收到的身份验证令牌。
do
州文件:
注意:这与可观察量的订阅不同。如果 可观察返回的 do 未订阅,副作用 观察者指定的永远不会发生。因此只是间谍 在现有执行中,它不会像 订阅确实如此。
我想实现的是,无论login()
的调用者是否订阅,都有这种副作用。我该怎么办?
正如@Maximus所解释的,根据设计,冷可观察(如http call(在订阅它们之前不会发出任何数据。因此,您的.do()
回调永远不会被调用。
另一方面,热可观察量将发出数据而不关心是否有订阅者。
您可以使用publish()
运算符将冷Observable
转换为ConnectableObservable
。当调用其connect()
方法时,该可观察对象将开始发出。
login(username: string, password: string): Observable < number > {
let body = new URLSearchParams();
body.append('grant_type', 'password');
body.append('username', username);
body.append('password', password);
let request = this.http.post(Constants.LOGIN_URL, body, null)
.do(res => {
if (res.status == 200) {
this.authTokenService.setAuthToken(res.json().auth_token);
}
})
.map(res => res.status)
.catch(err => {
return Observable.throw(err.status)
}).publish();
request.connect();
// type assertion because nobody needs to know it is a ConnectableObservable
return request as Observable < number > ;
}
正如@Maximus所说。如果订阅发生在 ajax 调用完成后,则不会收到结果通知。要处理这种情况,您可以使用publishReplay(1)
而不是简单的publish()
。PublishReplay(n)
将向新订阅者重复源Observable
发出的最后 n 个元素。
在下面的回答中,我假设您已经习惯了 AngularJS 中以前版本的HTTP
中Promises
提供的行为:
login(username: string, password: string): Observable<number> {
return this.http.post(Constants.LOGIN_URL, body, null)
.then(res => {
if (res.status == 200) {
this.authTokenService.setAuthToken(res.json().auth_token);
}
})
.then(res => res.status)
.catch(err => { return Observable.throw(err.status) });
从调用返回this.http.get()
可观察量cold
可观察量。这意味着除非有人订阅它,否则它不会开始做任何事情。这是设计使然。链接到返回的可观察量的所有运算符都不会执行任何操作,因为没有订阅。
您需要订阅才能发出请求,然后与未来的订阅者共享结果。我认为AsyncSubject
在这里是一个很好的候选人:
sent = false;
s = new AsyncSubject();
login(username: string, password: string): Observable<number> {
if (!this.sent) {
this.http.post(Constants.LOGIN_URL, body, null)
.do(res => {
if (res.status == 200) {
this.authTokenService.setAuthToken(res.json().auth_token);
}
})
.map(res => res.status)
.catch(err => { return Observable.throw(err.status) })
.subscribe(s);
this.sent = true;
}
return s;
}
这样,将只进行一次 http 调用,并且包含的所有运算符do
将只运行一次。之后,返回的结果将被缓存在 AsyncSubject 中,并将其传递给所有未来的订阅者。