【问题标题】:Template binding with function return Observable and async pipe带有函数返回 Observable 和异步管道的模板绑定
【发布时间】:2020-08-29 12:38:39
【问题描述】:

注意这是Angular template binding with Observable async pipe issue的简化问题

模板:

<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

【问题讨论】:

  • 我真的没有明白你的意思。在我看来,它按预期工作。 console.log 会在函数调用之后立即执行,无论您在返回的 observable 中有什么(顺便说一句,我假设您在第二个示例中忘记了它,即使用 pipe(delay)) 的示例)。

标签: angular rxjs rxjs6 rxjs-observables


【解决方案1】:

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

  1. 查看初始化模板调用foo$()
  2. foo$() 创建一个 -new- observable 并延迟发射
  3. observable 在延迟后发射
  4. 发射从async 管道内触发更改检测
  5. 更改检测调用模板中的foo$(),我们返回到第 2 步

目前还不清楚您要实现什么,但我认为您不应该从要在模板中使用的方法中返回 Observables。这些应该是只读类字段:

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

但是可以使用方法,但您必须确保该方法返回相同的Observable

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

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

example

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


如果你只返回of('delayed'),它不会进入无限循环的原因是因为Observable不是这样异步的。 Observable 将立即向async 管道返回一个值,当异步管道调用detectChanges() 时,什么都没有发生,因为它仍然与触发foo$() 模板调用的更改检测周期处于同一周期。


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

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

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

【讨论】:

  • @ArunMohan 您可以根据需要取消删除它。使用OnPush 的提议仍然是正确的,应该受到鼓励。仅仅因为答案是“错误的”,并不意味着它可能对其他人没有帮助:D
  • @PoulKruijt 我实际上是从属性装饰器开始的,但我发现它无法访问主机信息,我回退到方法装饰器
  • @GelinLuo 你找到了使用属性装饰器的方法吗?
  • @PoulKruijt 是的,我用 Property Decorator 完成了它。现在一切都好。非常感谢!老实说,我认为打字稿应该增强属性装饰器机制,以便它可以访问主机数据,例如访问主机的其他属性
  • 嗨@PoulKruijt,如果我正在进行动态页面渲染,假设所有字段都来自可配置的 JSON/YAML 文件,那么我需要从方法返回 obserable。你知道如何让它发挥作用吗?
猜你喜欢
  • 2019-07-11
  • 2017-11-20
  • 2019-08-02
  • 2019-12-19
  • 2017-02-12
  • 1970-01-01
  • 2020-08-29
  • 2019-07-17
  • 2017-11-30
相关资源
最近更新 更多