【问题标题】:One network call for each subscription每个订阅一次网络呼叫
【发布时间】:2018-07-11 11:07:42
【问题描述】:

我正在使用HTTPClient 发出post 请求,但是当我subscribeHTTPClient 返回的observable 时遇到了非常奇怪的行为:对于每个subscription,我得到一个post要求。意思是,如果我 subscribeobservable 5 次,我会收到 5 个 post 请求。太诡异了!

我正在我的 serverService 中发出以下请求:

  makePostReq<T>(reqObj: {url:string, body:any, headerData?:any}): Observable<T>{
    let headers = this.createHeaders(reqObj.headerData);
    reqObj.body, {headers:headers});
    return this.httpClient.post<T>(reqObj.url, reqObj.body, {headers:headers});
  }

在我的组件中,我调用makePostReq 如下:

 overviewInfo$: Observable<IOverviewInfo>;
 ngOnInit() {
    this.getOverviewInfo();
  }

  getOverviewInfo() {

    console.log('getOverviewInfo...');

    let url = this.constantsService.getOverViewInfoUrl();
    let body = {
      bot_id: this.bot_id,
      platform: this.selectedChannel,
      start_date: this.start_date,
      end_date: this.end_date
    };
        this.overviewInfo$ = this.serverService.makePostReq({url, body});

/*=== Now if I subscribe to overviewInfo 5 times, I will have 5 post request=== */

        this.overviewInfo$.subscribe((value) => {
          console.log(value);
        });
        this.overviewInfo$.subscribe((value) => {
          console.log(value);
        });
        this.overviewInfo$.subscribe((value) => {
          console.log(value);
        });
        this.overviewInfo$.subscribe((value) => {
          console.log(value);
        });
        this.overviewInfo$.subscribe((value) => {
          console.log(value);
        });
      }

截图:

编辑:

实际上,我不会多次订阅。相反,我在我的模板中使用了(overviewInfo$|async) 5 次,这与调用POST 5 次具有相同的效果。我用多个subscribe 询问了这个问题,以减少async 管道的不必要的复杂性。

【问题讨论】:

  • 当然可以。这就是订阅应该做的事情。你可以在很多地方订阅一个 Observable,一旦 POST 完成,它们都会被调用。您的 POST 没有被调用 5 次,来自 POST 调用的响应被发送到所有订阅的回调,即在您的情况下为 5。
  • @KaushikEvani Post 被调用了 5 次。我可以在网络选项卡中看到。我也可以附上截图。
  • 是的......我也通过自己的搜索找到了与以下相同的答案。显然这是 Observables 的设计。查看此angular issue 以及有关它的一些讨论。
  • @KaushikEvani 感谢您的链接。但是如果每个订阅都重新执行整个事情,人们如何使用异步管道(多次)?
  • 您应该只在模板中使用一次async 管道see this example

标签: angular observable


【解决方案1】:

我相信你正面临一个寒冷的观察。 post 方法会创建一个 observable,等待它被订阅,直到它触发请求。

从角度 documentationpost()

构造一个 Observable,当订阅它时,将导致配置的 POST 请求在服务器上执行。

根据您想要实现的目标,您可以使用share 运算符。每个订阅都不会触发新的发布请求,但会在发布请求完成时获得相同的数据。此外,它不会在订阅某些内容之前触发发布请求。如果您在请求完成后订阅,它应该创建一个新的。

 this.overviewInfo$ = this.serverService
                          .makePostReq({url, body})
                          .pipe(share());

multicast 操作符可以实现稍有不同的行为,这将立即触发发布请求。如果您在请求完成后订阅,您将不会收到任何数据。

 this.overviewInfo$ = this.serverService
                          .makePostReq({url, body})
                          .pipe(multicast());

对于良好的承诺时间,您可以使用toPromise,您可以随时使用.then

更多关于上述操作符的阅读:RxJS: Understanding the publish and share Operators

【讨论】:

  • 谢谢!我一直将 observables 视为“多重价值承诺”。承诺,一旦解决,就是不可变的对象。你可以使用它,导出它或者你做什么,在做.then()它会给你解决价值。我总是虽然 Observable 做同样的事情。我从事 Angular 开发已经 2 年了。想知道,我是如何在这种误解中生存下来的。
  • sharemulticast 的特殊别名,因此后者并不完全是“另一种选择”。
【解决方案2】:

我不知道您在同一个文件中多次订阅同一个方法的原因。相反,您可以只拥有一个subscription 并在那里做所有的无礼。您的组件代码调用了 makePostReq 5 次,这是正常行为。

无论哪种方式,如果您想多次订阅 observable 并且只想触发一次 http.post,那么 SubjectBehaviourSubject 最适合您的要求。

在服务中以this._subOverviewInfo.next(res.name)) 发送您的数据

服务器服务

private _subOverviewInfo: Subject<string> = new Subject<string>();
public overViewInfo$: Observable<string> = this._subOverviewInfo.asObservable();

makePostReq<T>(reqObj: {url:string, body:any, headerData?:any}): Observable<T>{
    let headers = this.createHeaders(reqObj.headerData);
    reqObj.body, {headers:headers});
    return this.httpClient.post<T>(reqObj.url, reqObj.body, {headers:headers})
    .pipe(map((res) => { 
           this._subOverviewInfo.next(res.name);  // emit subject
           return res; 
    }));
}

在组件中

直接拨打makePostReq()

 this.serverService.makePostReq({url, body}).subscribe();

改为订阅服务发出的subject

this.serverService.overViewInfo$.subscribe((value) => {
          console.log(value);
 });
 this.serverService.overViewInfo$.subscribe((value) => {
          console.log(value);
 });   
 this.serverService.overViewInfo$.subscribe((value) => {
          console.log(value);
});

【讨论】:

  • 请看我的编辑。此外,我的代码只调用了一次 makePostReq,而不是 5 次。
  • 你调用它一次。但是您的订阅多次调用它。它的工作方式与您假设的不同。
  • 知道了。谢谢!
猜你喜欢
  • 1970-01-01
  • 2019-12-13
  • 1970-01-01
  • 2023-03-04
  • 1970-01-01
  • 2013-12-27
  • 2013-08-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多