繁体   English   中英

Angular 2 http get observable 被调用两次

[英]Angular 2 http get observable called twice

在 Angular 2 v2.0.1 中,onInit 被调用两次。 (显然,当它被调用一次时我也做错了,但这不是现在的问题)

这是我的 Plunker: http ://plnkr.co/edit/SqAiY3j7ZDlFc8q3I212?p=preview

这是服务代码:

import {Injectable} from '@angular/core';
import {Http, Response} from '@angular/http';
import {Observable} from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/do';

@Injectable()
export class DemoService {


  constructor(private http:Http) { }

  // Uses http.get() to load a single JSON file
  getData() {
    return this.http.get('./src/data.json')
      .map((res:Response) => res.json())
      .do(data => console.log(data))
      .subscribe(data => {
        return <PageContent[]>data;
      }, error => console.log("there was an error!"));
  }
}

export class PageContent {
  constructor(public _id: string, 
  public tag: string, 
  public title: string, 
  public body?:string, 
  public image?: string) {}
}

...以及使用它的简单组件。

//our root app component
import {Component, NgModule, OnInit } from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'
import { DemoService, PageContent } from './service';
import { HttpModule } from '@angular/http';

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello {{name}}</h2>
    </div>
    <div *ngFor="let page of pages">
      {{ page.title }}
    </div>
  `
})
export class App implements OnInit {
  name:string;
  pages: PageContent[] = [];

  constructor(private _service: DemoService) {
    this.name = 'Angular2'
    this.loadData();  // <-- this is called once
  }

  ngOnInit() {
    //this.loadData();  // <-- this is called twice 
  }

  loadData(){
    this.pages = this._service.getData();
    console.log(this.pages);
  }
}

@NgModule({
  imports: [ BrowserModule, HttpModule ],
  declarations: [ App ],
  providers: [DemoService],
  bootstrap: [ App ]
})
export class AppModule {}

免责声明:它出错了,但是当从构造​​函数调用服务方法时,您可以看到它被提供了一次,但是当它在 ngOnInit 钩子中时它被调用了两次。

我的问题是,为什么从 OnInit 函数中调用它两次?

更新:所有答案的解决方案:

这是新的服务方法:

getData() {
    return this.http.get('./src/data.json')
        .map((res:Response) => res.json() as PageContent[]);
}

...这是新的组件方法:

loadData(){
    this._service.getData()
        .subscribe(data => this.pages = data);
}

您的subscribe应该放在组件而不是服务中。 原因是您的组件订阅了从服务返回的数据,稍后您可以根据需要取消订阅或添加更多控制(例如 denounce)。 更改后的代码将如下所示。

在您的组件中:

  ngOnInit() {
    this.loadData();
  }



  loadData(){
    this._service.getData().subscribe(data => this.pages = data);
  }

为您服务:

  getData() {
    return this.http.get('./src/data.json')
      .map((res:Response) => res.json());
  }

this._service.getData()返回一个主题,而不是一个 PageContent 列表。 你可以改变你的loadData像:

loadData() {
  this._service.getData().subscribe(data => this.pages = data);
  console.log("Load data !");
}

并删除getData方法的subscribe部分(来自DemoService )。 我刚刚对此进行了测试,并且ngOnInit被调用了一次

在英语中,当您订阅流 ( Observable ) 时,订阅块内的第一个函数内的代码将在该 observable 发出数据时执行。

如果您订阅两次,它将被调用两次,等等

由于您多次订阅,因此订阅块内的第一个函数(称为下一个函数)将被多次执行。

您应该只在ngOnInit订阅一次流。

当您想将数据发送到流上时,您可以为此使用 RXJS 主题,然后使主题随后使用 RXJS flatmap 发送到您订阅的流。

好的,我的第二个答案......看看这是否有帮助......

return subject.asObservable().flatMap((emit: any) => {

  return this.http[method](url, emit, this.options)
    .timeout(Config.http.timeout, new Error('timeout'))
    // emit provides access to the data emitted within the callback
    .map((response: any) => {
      return {emit, response};
    })
    .map(httpResponseMapCallback)
    .catch((err: any) => {
      return Observable.from([err.message || `${err.status} ${err.statusText}`]);
    });
}).publish().refCount();

其中 subject 是您要发送到的 RXJS 主题(使用 subject.next() 方法)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM