【问题标题】:Duplicated http request in ionic 2 with async pipe带有异步管道的 ionic 2 中的重复 http 请求
【发布时间】:2018-02-20 13:40:04
【问题描述】:

我是 ionic 2 的新手。我正在使用 ionic v3.6.1。

请注意,http 请求被触发 x 次,其中 x 是绑定到使用异步管道发布的请求。 因此,在这种情况下,http 请求被触发了 3 次。

请告知这是最佳做法。

提供者:

  getPostById(id: number) {
    return this.http.get(`${this.rootUrl}/${this.posts}/${id}`).map(res => res.json()).take(1);
  }

ts 文件:

post: Observable<Post>;
ionViewDidLoad() {
    this.postId = this.navParams.get('postId');
    console.log(this.postId);
    this.post = this.data.getPostById(this.postId);
  }

html

{{ (post | async)?.id }}
{{ (post | async)?.title}}
{{ (post | async)?.content}}

【问题讨论】:

    标签: angular typescript ionic2 rxjs ionic3


    【解决方案1】:

    share() 运算符

    每次订阅冷Observable 时,它都会被执行。避免这种行为的一种方法是让它变热。您可以使用.share()operator.publish().refCount() 的简写形式,有关这些运算符的更多信息,请参阅更多信息)来执行此操作:

    返回一个多播(共享)原始 Observable 的新 Observable。只要至少有一个订阅者,这个 Observable 就会被订阅并发送数据。当所有订阅者都取消订阅后,它将取消订阅源 Observable。因为 Observable 正在多播,所以它使流变热。这是.publish().refCount() 的别名。

    ionViewDidLoad() {
        this.postId = this.navParams.get('postId');
        console.log(this.postId);
        this.post = this.data.getPostById(this.postId).share();
      }
    

    有条件的怪癖

    如果您在模板中第一次使用 Observable,然后在有条件附加的元素 (*ngIf) 中再次使用它,您可能会遇到一些麻烦,因为 observable 已经运行并且没有将发出新数据。

    例如:

    模板:

    {{ (post | async)?.id }}
    <div *ngIf="post|async">
        {{ (post | async)?.title}}
        {{ (post | async)?.content}}
    </div>
    

    ts:

    post: Observable<Post>;
    ionViewDidLoad() {
        setTimeout(()=>this.show=true, 5000);
        this.postId = this.navParams.get('postId');
        console.log(this.postId);
        this.post = this.data.getPostById(this.postId).share();
      }
    

    这里shareoperator(单独)是不够的,因为发布了帖子,所以 ngIf 条件变为真,但子异步管道订阅了已经发出其值的 Observable。基本上它呈现这样的东西:

    myPostID
    <div></div>
    

    有两种方法可以解决这种情况:

    1. .publishReplay(n) :此操作符将重播 Observable 发出的最后 nth 个项目。我们将此运算符与refCount() 结合使用,它将跟踪订阅者的数量并在没有更多订阅者时重置冷可观察对象。

      this.post = this.data.getPostById(this.postId).publishReplay(1).refCount();
      
    2. 使用*ngIf="post |async as myPost" 这个语法是在 Angular 4(或者可能是 4.1,我不记得了)中引入的,它允许您将管道的结果存储在局部变量 myPost 中。 explainations here。所以你可以在你的 ts 代码中保留.share()part 并最终得到这样一个模板:

      {{ (post | async)?.id }}
      <div *ngIf="post|async as myPost">
          {{ myPost.title}}
          {{ myPost.content}}
      </div>
      

    关于publish()refCount() 的两句话:

    publish() 将常规 Observable 转换为 ConnectableObservable。这种 Observable 在其 connect() 方法被调用后立即开始发送数据(它使 observable 变热)。

    来自the docs

    Rx.Observable.prototype.publish([selector])

    返回一个可观察序列,该序列是在可连接的可观察序列上调用选择器的结果,该可连接的可观察序列共享对基础序列的单个订阅。

    refCount()ConnectableObservable上可用的方法,它的作用是在第一次订阅时调用connect()方法。如果所有订阅者都取消订阅,然后另一个订阅者请求订阅,则会再次调用它。

    来自the docs

    ConnectableObservable.prototype.refCount()

    只要至少有一个可观察序列订阅,就会返回一个可观察序列,该序列与源保持连接。

    【讨论】:

      【解决方案2】:

      您可以在此处遵循以下模式:

      .ts

      post: Post;
      ionViewDidLoad() {
          this.postId = this.navParams.get('postId');
          console.log(this.postId);
          this.data.getPostById(this.postId).subscribe(data => {
              this.post= data;
          });
      
        }
      

      模板如下:

      .html

      {{ post?.id }}
      {{ post?.title}}
      {{ post?.content}}
      

      【讨论】:

      • 那么在 html 中使用订阅比使用异步管道更可取吗?
      • 现在你有一个问题。首先尝试使用上述方法解决该问题。有很多方法可以做同样的事情。没有人能说这比那个更好,就像那样......所以试试上面的方法,让我们知道你的结果。
      • 顺便说一句 @Sampath post 不是 Observable&lt;Post&gt; 只是 Post
      • 是的,已更正。谢谢,@n00dl3 :)
      猜你喜欢
      • 2018-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-26
      相关资源
      最近更新 更多