模板绑定函数 return Observable 和异步管道

Template binding with function return Observable and async pipe

注意这是

的简化问题

模板:

<div>{{foo()$ | async}}</div>

源代码:

import { Component } from "@angular/core";
import { BehaviorSubject, of, Observable } from "rxjs";
import { tap, delay, map, switchMap, concatMap } from "rxjs/operators";

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  private index = 0;
  foo$(): Observable<any> {
    console.log("aaa")
    return of("Delayed");
  }
}

以上代码按预期工作:

但是如果我将 .pipe(delay(1)) 添加到 foo$():

  foo$(): Observable<any> {
    return of("Delayed").pipe(delay(1));
  }

它不会工作并在控制台日志中保留 "aaa"。

https://stackblitz.com/edit/angular-qbhkg3

从模板调用的方法,在每个更改检测周期调用。因为您使用的是 async 管道,所以每次发出都会触发更改检测。所以基本上你正在创建一个无限循环,这就是为什么它永远不会显示一个值,因为变化检测永远不会完成:

  1. 视图初始化模板调用 foo$()
  2. foo$() 创建一个 -new- observable 并延迟 emit
  3. 可观察对象在延迟后发出
  4. 发射触发了 async 管道内的变化检测
  5. 更改检测从模板调用 foo$(),我们回到第 2 步

不太清楚您要实现的目标,但我认为您不应该 return Observables 从要在模板中使用的方法。这些应该是只读的 class 字段:

readonly foo$ = of("Delayed").pipe(delay(1));

但是可以使用一个方法,但是你必须确保这个方法return是相同的Observable:

private readonly _foo$: Observable<any> = of("Delayed").pipe(delay(1));

foo$(): Observable<any> {
  console.log('here');
  return this._foo$;
}

example

因为可观察对象保持不变 (===),所以一切都很好。将 pipe 添加到 Observable 后,您将创建一个新引用并返回无限循环。


如果你只是 return of('delayed'),它不会进入无限循环的原因是因为 Observable 不是异步的。 Observable 将立即 return 一个值到 async 管道,当异步管道调用 detectChanges() 时什么也没有发生,因为它仍然与触发foo$() 模板调用。


我看到您还链接了您之前发布的一个涉及装饰器使用的问题。您应该将该装饰器更改为 class 字段装饰器,然后您可以执行以下操作:

@NeedsElement(sp(115621), ap(116215))
readonly insuredType$!: Observable<string>;

我想我可以想出一种方法让它与方法调用一起工作,但在我深入研究之前,我首先想知道为什么你希望它成为方法调用第一名