模板绑定函数 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"。
从模板调用的方法,在每个更改检测周期调用。因为您使用的是 async
管道,所以每次发出都会触发更改检测。所以基本上你正在创建一个无限循环,这就是为什么它永远不会显示一个值,因为变化检测永远不会完成:
- 视图初始化模板调用
foo$()
foo$()
创建一个 -new- observable 并延迟 emit
- 可观察对象在延迟后发出
- 发射触发了
async
管道内的变化检测
- 更改检测从模板调用
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$;
}
因为可观察对象保持不变 (===
),所以一切都很好。将 pipe
添加到 Observable
后,您将创建一个新引用并返回无限循环。
如果你只是 return of('delayed')
,它不会进入无限循环的原因是因为 Observable
不是异步的。 Observable 将立即 return 一个值到 async
管道,当异步管道调用 detectChanges()
时什么也没有发生,因为它仍然与触发foo$()
模板调用。
我看到您还链接了您之前发布的一个涉及装饰器使用的问题。您应该将该装饰器更改为 class 字段装饰器,然后您可以执行以下操作:
@NeedsElement(sp(115621), ap(116215))
readonly insuredType$!: Observable<string>;
我想我可以想出一种方法让它与方法调用一起工作,但在我深入研究之前,我首先想知道为什么你希望它成为方法调用第一名
注意这是
模板:
<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"。
从模板调用的方法,在每个更改检测周期调用。因为您使用的是 async
管道,所以每次发出都会触发更改检测。所以基本上你正在创建一个无限循环,这就是为什么它永远不会显示一个值,因为变化检测永远不会完成:
- 视图初始化模板调用
foo$()
foo$()
创建一个 -new- observable 并延迟 emit- 可观察对象在延迟后发出
- 发射触发了
async
管道内的变化检测 - 更改检测从模板调用
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$;
}
因为可观察对象保持不变 (===
),所以一切都很好。将 pipe
添加到 Observable
后,您将创建一个新引用并返回无限循环。
如果你只是 return of('delayed')
,它不会进入无限循环的原因是因为 Observable
不是异步的。 Observable 将立即 return 一个值到 async
管道,当异步管道调用 detectChanges()
时什么也没有发生,因为它仍然与触发foo$()
模板调用。
我看到您还链接了您之前发布的一个涉及装饰器使用的问题。您应该将该装饰器更改为 class 字段装饰器,然后您可以执行以下操作:
@NeedsElement(sp(115621), ap(116215))
readonly insuredType$!: Observable<string>;
我想我可以想出一种方法让它与方法调用一起工作,但在我深入研究之前,我首先想知道为什么你希望它成为方法调用第一名