【问题标题】:Check if Observable (http request) returned a value and if it didnt wait for it?检查 Observable(http 请求)是否返回了一个值,如果它没有等待它?
【发布时间】:2019-06-27 16:09:41
【问题描述】:

我在 Angular 应用程序 (calendarComponent) 中有一个日历,它通过来自 mongodb 的 firebase 云函数获取其条目(通过名为 calendarService 的服务)。要创建一个新条目,我会弹出一个角度材质对话框(addEventComponent)。此对话框需要数据库中的一些数据才能工作。到目前为止,对话框组件从 calendarService 请求数据,每次我想添加一个条目时它都会发出一个新的 http 请求。除了有明显的延迟外,它可能会根据 Firebase 数据计划引发成本增加。 理想情况下,calendarComponent 会从 ngOnInit 上的 calendarService 请求数据,并根据请求将其传递给 addEventComponent,但这仅在单击新条目对话框时 http 请求完成时才有效。 我对 angular 和 rxjs 太缺乏经验,无法以一种不丑陋的方式解决这个问题。

我最初尝试的是这样的:

calendarComponent

内部
requiredData: RequiredData[];

ngOnInit() {
  this.calendarService.getRequiredData().subscribe(response => {
    this.requiredData = response.data;
  });
}

addNewEntry () {

  const dialogData = this.requiredData;

  const dialogRef = this.dialogModal.open(AddEventComponent, {
    data: { requiredData: dialogData },
  });

}

(CalendarService 只是返回一个 http.get() 请求,所以我没有在这里写代码。)

只要 http 请求不需要永远,它就可以很好地工作。作为一个临时解决方案,我像以前一样触发了 http 请求,但将响应保存在 calenderService 中并返回了一个可观察的。看起来像这样:

calendarComponent

内部
ngOnInit() {
  this.calendarService.getRequiredData();
}

calendarService

private requiredData$ = new Subject<RequiredData>();
requiredData: RequiredData[];

getRequiredData () {
  this.http.get<{ _msg: string, reqData: RequiredData[] }>(API_URL)
    .subscribe(response => {
      this.requiredData = response.reqData;
      this.requiredData$.next([...this.requiredData]);
    });
}

getReqData () {
  return this.requiredData$.asObservable();
}

我的问题发生在 AddEventComponent

requiredData: RequiredData[];

ngOnInit() {
  this.calendarService.getReqData().subscribe(response => {
    this.useTheRequiredData(response);
  });
}

上面的代码不起作用,因为如果请求已经完成,订阅不会触发。所以我需要的是一种更智能的方法来执行此操作,或者是一个代码来检查可观察对象是否已经发出值,如果没有,则等待第一次发出,然后触发后续函数。有点像下面这样,但不那么粗糙和工作。

AddEventComponent

里面
requiredData: RequiredData[];

ngOnInit() {

  if (this.calendarService.requiredData) {
    this.useTheRequiredData(this.calendarService.requiredData);
  } else {
    this.calendarService.getReqData().subscribe(response => {
      this.useTheRequiredData(response);
    });
  }
}

感谢每一个帮助。

似乎可行的是 (AddEventComponent)

this.calendarService.requiredData
  ? this.useTheRequiredData(this.calendarService.requiredData)
  : this.calendarService.getReqData().pipe(
    take(1),
    tap(response => {
      this.useTheRequiredData(response);
    })
  ).subscribe();

主要让我感到困惑的是使用纯管道(模板中的角度过滤器管道,而不是 rxjs 管道),并没有意识到很长。

【问题讨论】:

    标签: angular rxjs angular-material


    【解决方案1】:

    您是否考虑过使用 RxJS ReplaySubject 而不是常规的 SubjectReplaySubject 将在订阅者订阅时向订阅者发送最新值:

    https://medium.com/@luukgruijs/understanding-rxjs-behaviorsubject-replaysubject-and-asyncsubject-8cc061f1cfc0

    您不妨将ReplaySubject 公开为只读属性,并在CalendarService 的构造函数中对其进行初始化,而不是您的getter 函数:

    private requiredDataObservable$: Observable<RequiredData[]>;
    
    [...]
    
    constructor(...) {
      this.requiredDataObservable$ = this.requiredData$.asObservable();
    }
    

    就我个人而言,我使用$ 后缀作为我公开的可观察对象,并使用不带它的相应名称作为主题,但这只是我采用的约定:

      /** data subject to propagate changes */
      private data: ReplaySubject<T[]>;
    
      /** data observable exposed for subscribers */
      protected data$: Observable<T[]>;
    

    【讨论】:

    • 这听起来是个好主意,非常感谢。我对 Angular 和 rxjs 还是很陌生,官方文档很长。
    猜你喜欢
    • 2018-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-03
    • 1970-01-01
    • 2020-06-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多