对我来说有点head头
基本上,我正在实现一个简单的角度应用程序,以显示名称并将其重新分配给ID。
export class Assignment {
name: string;
id?: string;
}
为此,后端发布端点:
GET /assignments
> [{"1": "id-a"},{"2": ""}] // where "2" is unassigned
PUT /assignments/:name/:id
GET /stream
> text/event-stream of new assignments as type="update", data = {"name": "1", "id":"id-a"} ...
前端具有公开所有这些终结点的服务,流的设置如下:
export class HttpService {
private source: EventSource;
constructor(private http: HttpClient, private zone: NgZone) {
this.source = new EventSource('/stream');
}
...
public getStream(): Observable<Assignment> {
return new Observable(observer => {
console.log('subscribed to stream');
this.source.addEventListener('update',(evt: MessageEvent) =>
this.zone.run(() => observer.next(JSON.parse(evt.data))));
this.source.onerror = evt => observer.error(evt);
return () => { console.log('unsubscribing'); }
});
}
}
我创建了一个组件来非常简单地保存一项任务
template: `<div> {{assignment.name}} = {{assignment.id}} <div>`
@Input() assignment: Assignment
现在抓到了,我的应用程序组件设置如下:
模板:
<app-assignment *ngFor="let item of assignments" [assignment]="getUpdatesForName(item) | async"></app-assignment >
组件:
export class MainComponent implements OnInit {
public selected: string;
public assignments: Assignment[];
public update$: Observable<Assignment>;
constructor(private httpservice: HttpService) {
}
ngOnInit() {
this.httpservice.getAssignments().subscribe( it => this.assignments = it);
this.update$ = this.httpservice.getStream();
}
public selectSound(soundid: string) {
this.selected = soundid;
}
public getUpdatesForName(assignment: Assignment): Observable<Assignment> {
return concat(
of( assignment ),
this.update$.pipe(
filter(it => it.name=== assignment.name)
)
);
}
}
问题在于,当我通过其余API更改工作分配时,UI上再也没有更新。 取而代之的是,日志稳定地填充了“已订阅”和“未订阅”消息。 因此,异步管道似乎一遍又一遍地进行订阅和取消订阅,而且从未完成任何事情。
我的第一个假设是,总是在源中添加新的侦听器会阻塞某些内容,因此我尝试持有一组订阅者和一个消息侦听器
export class HttpService {
private source: EventSource;
private subscribers :Subscriber<Assignment>[] = [];
constructor(private http: HttpClient, private zone: NgZone) {
this.source = new EventSource('/stream');
this.source.addEventListener('update',(evt: MessageEvent) => this.zone.run(() => this.subscribers.forEach(it => it.next(JSON.parse(evt.data)), false)));
this.source.onerror = evt => console.log('error in stream' + evt)
}
...
public getStream(): Observable<Assignment> {
return new Observable(observer => {
console.log('subscribed to stream');
this.subscribers.push(observer)
return () => {
this.subscribers = this.subscribers.filter(it => it !== observer)
};
});
}
没有任何改变。
当我通过传递Observable并在子组件的subscribe(input => localmember = input)
中进行OnInit
替换异步管道时,整个工作按预期进行
编辑:
我进行了一些测试,发现使用重播主题使其可以准确地处理适合重播缓冲区的邮件数量。
因此,我假设每次CD周期发生时异步管道都会重新订阅,并且在结束时取消订阅?但是,如何知道CD末尾取消订阅的新项目何时发出?
答案 0 :(得分:0)
好,知道了,但是我可以看到有人遇到了这个问题,不想删除我的问题。
基本上,感谢https://www.lucidchart.com/techblog/2019/10/14/angulars-async-pipe-intricacies/
它说:
虽然不是本文的重点,但这里还有另一个重要说明 是异步管道将仅返回从 如果输入仍然是完全相同的Promise实例,则承诺。如果 您正在调用异步方法或创建新Promise的方法 每次调用时,异步管道都会假定它的任何值 具有不再相关,因此可能永远不会产生可用的 值。
按照我在CD上进行设置的方式,角度将重新评估子组件[assignment]="getUpdatesForName(item) | async"
的输入。
这是因为我要通过其过滤的过滤器将始终返回新的Observable,从而导致恒定的sub-unsub模式,并且永远不会产生可用的值。
解决方案是一次创建所有过滤的Observable,然后将它们存储到Map>。