Angular 2 observable 订阅两次执行调用两次
Angular 2 observable subscribing twice executes call twice
问题
我订阅了一个 httpClient.get observable 两次。但是,这意味着我的调用被执行了两次。这是为什么?
证明
对于我执行的每个 subscribe(),我都会在登录页面中得到另一行。
代码(来自登录页面按钮的 onSubmit())
var httpHeaders = new HttpHeaders()
.append("Authorization", 'Basic ' + btoa(this.username + ':' + this.password));
var observable = this.httpClient.get('api/version/secured', { headers: httpHeaders});
observable.subscribe(
() => {
console.log('First request completed');
},
(error: HttpErrorResponse) => {
console.log('First request error');
}
);
observable.subscribe(
() => {
console.log('Second request completed');
},
(error: HttpErrorResponse) => {
console.log('Second request error');
}
);
控制台
zone.js:2935 GET http://localhost:4200/api/version/secured 401 (Unauthorized)
login.component.ts:54 First request error
zone.js:2935 GET http://localhost:4200/api/version/secured 401 (Unauthorized)
login.component.ts:62 First request error
无关背景
我有一个 LogonService 对象来处理我的所有登录功能。它包含一个布尔变量,显示我是否登录。每当我调用登录函数时,它都会订阅 httpClient.get 的可观察对象,以将登录变量设置为 true 或 false。但是登录函数也是 returns 被订阅的可观察对象。我花了一些时间 link 双重订阅的双重请求。如果有比通过变量跟踪登录更好的方法,请告诉我!我正在努力学习 angular :)
http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html
Invokes an execution of an Observable and registers Observer handlers
for notifications it will emit.
您可以对 HttpClient.get
的结果使用 share
运算符,如下所示:
var observable = this.httpClient.get('api/version/secured', { headers: httpHeaders })
.pipe(share());
您需要在脚本顶部添加以下导入:
import { share } from 'rxjs/operators';
share
运算符生成可观察的 hot
,即在订阅者之间共享。但还有很多,我建议 this article 深入研究(当然你也可以 google 向上 hot vs cold observables
找到更多)。
你的 observable 是冷的:
An observable is cold if the producer of its notifications is created
whenever an observer subscribes to the observable. For example, a
timer observable is cold; each time a subscription is made, a new
timer is created.
您需要 multicast
您的 Observable,或者换句话说,让它变热:
An observable is hot if the producer of its notifications is not
created each time an observer subscribes to the observable. For
example, an observable created using fromEvent is hot; the element
that produces the events exists in the DOM — it’s not created when the
observer is subscribed.
为此,您可以使用 share 运算符,但它仍然不能保证您进行一次 http 调用。 Share 将 multicast
您的可观察对象,使其在订阅者之间共享,但是一旦 http 调用完成,它将为新订阅者进行新的 http 调用。
如果您想要缓存行为(执行一次调用,然后在每个订阅者订阅时向其提供值),您应该使用 publishReplay().refCount()
.
进一步阅读:
除了上述答案之外,您还可以将您的 http
服务分配给 observable,然后订阅获取数据。例如:
export class App implements OnInit {
lessons$: Observable<Lessons[]>;
constructor(private lessonsService: lessonsService) {
}
ngOnInit() {
this.lessons$ = this.lessonsService.loadLessons().publishLast().refCount();
this.lessons$.subscribe(
() => console.log('lessons loaded'),
console.error
);
}
}
问题
我订阅了一个 httpClient.get observable 两次。但是,这意味着我的调用被执行了两次。这是为什么?
证明
对于我执行的每个 subscribe(),我都会在登录页面中得到另一行。
代码(来自登录页面按钮的 onSubmit())
var httpHeaders = new HttpHeaders()
.append("Authorization", 'Basic ' + btoa(this.username + ':' + this.password));
var observable = this.httpClient.get('api/version/secured', { headers: httpHeaders});
observable.subscribe(
() => {
console.log('First request completed');
},
(error: HttpErrorResponse) => {
console.log('First request error');
}
);
observable.subscribe(
() => {
console.log('Second request completed');
},
(error: HttpErrorResponse) => {
console.log('Second request error');
}
);
控制台
zone.js:2935 GET http://localhost:4200/api/version/secured 401 (Unauthorized)
login.component.ts:54 First request error
zone.js:2935 GET http://localhost:4200/api/version/secured 401 (Unauthorized)
login.component.ts:62 First request error
无关背景
我有一个 LogonService 对象来处理我的所有登录功能。它包含一个布尔变量,显示我是否登录。每当我调用登录函数时,它都会订阅 httpClient.get 的可观察对象,以将登录变量设置为 true 或 false。但是登录函数也是 returns 被订阅的可观察对象。我花了一些时间 link 双重订阅的双重请求。如果有比通过变量跟踪登录更好的方法,请告诉我!我正在努力学习 angular :)
http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html
Invokes an execution of an Observable and registers Observer handlers for notifications it will emit.
您可以对 HttpClient.get
的结果使用 share
运算符,如下所示:
var observable = this.httpClient.get('api/version/secured', { headers: httpHeaders })
.pipe(share());
您需要在脚本顶部添加以下导入:
import { share } from 'rxjs/operators';
share
运算符生成可观察的 hot
,即在订阅者之间共享。但还有很多,我建议 this article 深入研究(当然你也可以 google 向上 hot vs cold observables
找到更多)。
你的 observable 是冷的:
An observable is cold if the producer of its notifications is created whenever an observer subscribes to the observable. For example, a timer observable is cold; each time a subscription is made, a new timer is created.
您需要 multicast
您的 Observable,或者换句话说,让它变热:
An observable is hot if the producer of its notifications is not created each time an observer subscribes to the observable. For example, an observable created using fromEvent is hot; the element that produces the events exists in the DOM — it’s not created when the observer is subscribed.
为此,您可以使用 share 运算符,但它仍然不能保证您进行一次 http 调用。 Share 将 multicast
您的可观察对象,使其在订阅者之间共享,但是一旦 http 调用完成,它将为新订阅者进行新的 http 调用。
如果您想要缓存行为(执行一次调用,然后在每个订阅者订阅时向其提供值),您应该使用 publishReplay().refCount()
.
进一步阅读:
除了上述答案之外,您还可以将您的 http
服务分配给 observable,然后订阅获取数据。例如:
export class App implements OnInit {
lessons$: Observable<Lessons[]>;
constructor(private lessonsService: lessonsService) {
}
ngOnInit() {
this.lessons$ = this.lessonsService.loadLessons().publishLast().refCount();
this.lessons$.subscribe(
() => console.log('lessons loaded'),
console.error
);
}
}