同步阻止订阅呼叫基于可观察的自定义ReplaySubject

时间:2020-11-12 10:13:46

标签: angular observable rxjs-observables

该视图包含以下元素:

RewriteRule ^(.*)$-registration category.php?link=$1 [NC,L,QSA]

调用组件方法时:

<div *ngIf="showMe">Hello</div>

该元素在视图中显示在所有downloadDemo(): void { this.download$ = this.downloadService.downloadUrlAsBlobWithProgressAndSaveInFile('assets/skypeforlinux-64.deb', 'demo') this.download$.subscribe((download: Download) => { this.showMe = true; console.log('Progress: ' + download.progress); }) } 记录器之前。这就是应该的方式。这种基于HTTP的下载效果很好。

但是,调用组件方法时:

Progress

该元素在所有downloadSoundtrack(soundtrack: Soundtrack): void { const fileName: string = soundtrack.name + '.' + MIDI_FILE_SUFFIX; const progress$: Observable<ProgressTask<Uint8Array>> = this.midiService.progressiveCreateSoundtrackMidi(soundtrack); this.download$ = this.downloadService.downloadObservableDataAsBlobWithProgressAndSaveInFile(progress$, fileName); this.download$.subscribe((download: Download) => { this.showMe = true; console.log('Progress: ' + download.progress); }) } 记录器之后最后在视图中显示。这不是应该的。此基于Progress的自定义可观察项无法正常工作。实际上,该元素应该显示在所有ReplaySubject记录器之前而不是之后。

我想看看是否有一个订阅呼叫被阻止。

所以我将两种方法更改为:

Progress

以下是调用downloadSoundtrack(soundtrack: Soundtrack): void { const fileName: string = soundtrack.name + '.' + MIDI_FILE_SUFFIX; const progress$: Observable<ProgressTask<Uint8Array>> = this.midiService.progressiveCreateSoundtrackMidi(soundtrack); this.download$ = this.downloadService.downloadObservableDataAsBlobWithProgressAndSaveInFile(progress$, fileName); this.showMe = true; this.download$.subscribe((download: Download) => { console.log('Progress: ' + download.progress); }); console.log('Call done'); } downloadDemo(): void { this.download$ = this.downloadService.downloadUrlAsBlobWithProgressAndSaveInFile('assets/skypeforlinux-64.deb', 'demo') this.showMe = true; this.download$.subscribe((download: Download) => { console.log('Progress: ' + download.progress); }); console.log('Call done'); } 方法时的记录器:

downloadDemo()

我们可以看到Progress: 0 Call done Progress: 0 Progress: 0 Progress: 2 Progress: 3 通话没有阻塞。

以下是调用subscribe()方法时的记录器:

downloadSoundtrack()

我们可以看到Progress: 96 Progress: 97 Progress: 100 Call done 通话被阻止。

添加明确的subscribe()调用没有区别:

this.detectChanges();

它仍然显示在所有downloadSoundtrack(soundtrack: Soundtrack): void { const fileName: string = soundtrack.name + '.' + MIDI_FILE_SUFFIX; const progress$: Observable<ProgressTask<Uint8Array>> = this.midiService.progressiveCreateSoundtrackMidi(soundtrack); this.download$ = this.downloadService.downloadObservableDataAsBlobWithProgressAndSaveInFile(progress$, fileName); this.download$.subscribe((download: Download) => { this.showMe = true; this.detectChanges(); console.log('Progress: ' + download.progress); }) } 记录器之后。

我还尝试了一些显式订阅来代替模板中的Progress,但是它没有任何帮助:

*ngIf="download$ | async as download"

长期运行的服务:

downloadInProgress(soundtrack: Soundtrack): boolean {
  let inProgress: boolean = false;
  if (soundtrack.download) {
    if (soundtrack.download.progress > 0 && soundtrack.download.progress < 100) {
      inProgress = true;
    } else if (soundtrack.download.progress == 100) {
      console.log('complete');
      soundtrack.download = undefined;
    }
  }
  console.log('inProgress ' + inProgress);
  return inProgress;
}

有50ms的睡眠调用,这会减慢文件创建的速度,以便留出足够的时间。

下载服务的实现基于this article

我正在使用Angular 9.1.0

1 个答案:

答案 0 :(得分:0)

为简单起见,我建议改用更具反应性的状态驱动方法,在此方法中,您可以执行以下操作:

1。

soundtracks从数组更改为public readonly soundtracks: Observable<Soundtrack[]> = this.soundtracksSubject.asObservable(),以使UI可以注册更改。 this.soundtracksSubjectprivate readonly soundtracksSubject: BehaviorSubject<Soundtrack[]> = new BehaviorSubject([]);,然后可以用来触发soundtracks的观察者刷新。收到HTTP响应时,您无需设置this.soundtracks = soundtracks;而是调用this.soundtracksSubject.next(soundtracks))

在进行实际下载(soundtrack.download = download;)时,不仅要在更改后更改模型,还必须再次调用主题以将模型中的更改传播给侦听器:

const updatedSoundtracks: Soundtrack[] = this.soundtracksSubject.value.map(existingSoundtrack => existingSoundtrack);
const soundtrack: Soundtrack = updatedSoundtracks.find(existingSoundtrack => soundtrack.name === existingSoundtrack.name); // Or whatever identifies your soundtrack

if (soundtrack) {
    soundtrack.download = download;
    this.soundtracksSubject.next(updatedSoundtracks);
}

将用户界面从<tr *ngFor="let soundtrack of soundtracks">更改为<tr *ngFor="let soundtrack of soundtracks | async">,以解析Observable以便在Angular组件中使用它。这也意味着您的组件将注册soundtracks上的更改,并在有人调用主题/可观察对象时得到通知。

ObservableBehaviorSubject都是RxJS概念(import {BehaviorSubject, Observable} from "rxjs/index";),值得研究,因为它们使您的生活变得更加轻松。