我有这个功能:
/**
* 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没有订阅,副作用 观察者指定的情况永远不会发生。因此,只是间谍 在现有执行中,它不会触发执行就好 订阅确实。
我想要实现的是,无论login()
的来电者是否订阅,都会产生这种副作用。我该怎么办?
答案 0 :(得分:2)
正如@Maximus所解释的那样,在设计之前,冷Observable(如http调用)在订阅它们之前不会发出任何数据。所以你的.do()
回调永远不会被调用。
您可以使用Observable
运算符将您的冷ConnectableObservable
转换为publish()
。 Observable将在调用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个元素。
答案 1 :(得分:1)
在下面的回答中,我假设您习惯了Private Sub textBox5_KeyPress(sender As System.Object, e As System.Windows.Forms.KeyPressEventArgs) Handles textBox5.KeyPress
If Asc(e.KeyChar) <> 8 Then
If Asc(e.KeyChar) < 48 Or Asc(e.KeyChar) > 57 Then
e.Handled = True
End If
End If
End Sub
在AngularJS中以前版本的Promises
中提供的行为:
HTTP
从 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) });
调用返回的observable是this.http.get()
可观察的。这意味着除非有人订阅,否则它不会开始做任何事情。那是设计上的。您链接到返回的观察者的所有操作员都不会做任何事情,因为没有订阅。
您需要订阅提出请求,然后与未来订阅者共享结果。我认为cold
在这里是一个很好的候选人:
AsyncSubject
这样只会进行一次http调用,所有包含 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;
}
的运算符只会运行一次。之后,返回的结果将缓存在do
中,并将其传递给所有未来的订阅者。