我有这个功能:
/**
* 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
州的文件:
注意:这与Observable上的订阅不同 . 如果没有订阅do返回的Observable,Observer指定的副作用将永远不会发生 . 因此,它只是简单地监视现有的执行,它不会像订阅那样触发执行 .
我想要实现的是,无论 login()
的调用者是否订阅,都会产生这种副作用 . 我该怎么办?
2 回答
正如@Maximus所解释的那样,根据设计,冷Observable(如http调用)在订阅它们之前不会发出任何数据 . 所以你的
.do()
回调永远不会被调用 .另一方面,如果有订户,热的Observable将发出数据而不关心 .
您可以使用
publish()
运算符将冷Observable
转换为ConnectableObservable
. Observable将在调用connect()
方法时开始发射 .正如@Maximus所说 . 如果订阅在ajax调用完成后发生,则不会收到结果通知 . 要处理这种情况,您可以使用
publishReplay(1)
而不是简单的publish()
.PublishReplay(n)
将重复源Observable
向新订阅者发出的最后第n个元素 .在下面的答案中,我假设您习惯了
Promises
在AngularJS的HTTP
之前版本中提供的行为:从
this.http.get()
调用返回的observable是cold
可观察的 . 这意味着除非有人订阅,否则它不会开始做任何事情 . 那是设计上的 . 您链接到返回的可观察对象的所有运算符都没有订阅 .您需要订阅发出请求,然后与未来的订阅者共享结果 . 我认为
AsyncSubject
是一个很好的候选人:这样只会进行一次http调用,所有运算符包含
do
只会运行一次 . 之后,返回的结果将缓存在AsyncSubject
中,并将其传递给所有未来的订阅者 .