带有异步管道的 ionic 2 中的重复 http 请求

Posted

技术标签:

【中文标题】带有异步管道的 ionic 2 中的重复 http 请求【英文标题】:Duplicated http request in ionic 2 with async pipe 【发布时间】: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

【问题讨论】:

【参考方案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>

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

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

    this.post = this.data.getPostById(this.postId).publishReplay(1).refCount();
    

    使用*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 :)

以上是关于带有异步管道的 ionic 2 中的重复 http 请求的主要内容,如果未能解决你的问题,请参考以下文章

在模板中使用带有异步管道的 Observable 时显示加载

离子/角度:找不到管道“异步”

带有 ChangeDetectionStrategy.OnPush 和异步管道的 Angular 2 Observable 不起作用

ngFor 块内模板中的异步管道触发 http GET 调用循环

带有 ngSwitch 的条件按钮也带有来自异步管道数组的 ngFor

无法使用带有 DCE 管道的异步 RPC 将数据推送到服务器