Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/29.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 以角度2获取一次可观测数据_Javascript_Angular_Rxjs_Observable - Fatal编程技术网

Javascript 以角度2获取一次可观测数据

Javascript 以角度2获取一次可观测数据,javascript,angular,rxjs,observable,Javascript,Angular,Rxjs,Observable,我有一个服务,我的Angular 2组件多次使用。它从Web API获取客户数据,并返回一个可观察的: getCustomers() { return this.http .get(this.baseURI + this.url) .map((r: Response) => { let a = r.json() as Customer[]; return a;

我有一个服务,我的Angular 2组件多次使用。它从Web API获取客户数据,并返回一个可观察的:

getCustomers() {
   return this.http
        .get(this.baseURI + this.url)
        .map((r: Response) => {
            let a = r.json() as Customer[];                       
            return a;                         
        });               
}    
this.customerService.getCustomers().subscribe(v => this.items = v);
我将此服务注入到我的根组件中,并且在每个想要访问客户的组件中,我只订阅了可观察到的服务:

getCustomers() {
   return this.http
        .get(this.baseURI + this.url)
        .map((r: Response) => {
            let a = r.json() as Customer[];                       
            return a;                         
        });               
}    
this.customerService.getCustomers().subscribe(v => this.items = v);
然而,订阅我的Observable的每个组件都会导致HTTP请求的另一次执行。但是只获取一次数据就足够了。 如果我尝试share(),它无法解决我的问题:

getCustomers() {
   return this.http
        .get(this.baseURI + this.url)
        .map((r: Response) => {
            let a = r.json() as Customer[];                       
            return a;                         
        }).share();               
}   

还是一样的问题。任何我必须使用的操作符只能获取一次数据的建议?

共享操作符允许对多个观察者使用同一流的结果。这可能很好,但是每次调用
getCustomers()
,您都会生成一个新的可观察流,因为您没有多次订阅此流,所以调用
share()
没有意义

如果您想与多个观察者共享数据,但只进行一次http调用,那么您只需创建第二个流,由http流馈送,其中包含数据。之后,您的所有组件都可以订阅它

代码可能是这样的

@Injectable()
class FooBar {

    public dataStream:Subject<any> = new Subject();

    constructor(private http:Http) {}

    public getCustomers() {
        return this.http
        .get(this.baseURI + this.url)
        .map((response:Response) => response.json())
        .map((data) => {
            this.dataStream.next(data); 
            return data;
        })
    }

}


@Component({})
class BarFooHttpCaller {
    constructor(private foobar:Foobar) {}

    ngOnInit() {
        this.foobar.getCustomers().subscribe(() => { console.log('http done') });
        this.foobar.dataStream.subscribe((data) => {
            console.log('new data', data);
        })
    }
}

@Component({})
class OtherBarFoo {
    constructor(private foobar:Foobar) {}

    ngOnInit() {
        this.foobar.dataStream.subscribe((data) => {
            console.log('new data', data);
        })
    }
}
@Injectable()
福巴级{
公共数据流:主题=新主题();
构造函数(私有http:http){}
公众客户(){
返回此文件。http
.get(this.baseURI+this.url)
.map((response:response)=>response.json())
.map((数据)=>{
this.dataStream.next(数据);
返回数据;
})
}
}
@组件({})
类BarFooHttpCaller{
构造函数(私有foobar:foobar){}
恩戈尼尼特(){
this.foobar.getCustomers().subscribe(()=>{console.log('httpdone')});
this.foobar.dataStream.subscribe((数据)=>{
console.log('新数据',数据);
})
}
}
@组件({})
类OtherBarFoo{
构造函数(私有foobar:foobar){}
恩戈尼尼特(){
this.foobar.dataStream.subscribe((数据)=>{
console.log('新数据',数据);
})
}
}

我将创建一个父容器,提取一次数据,然后使用@Input将其传递给子组件

家长:

@Component({
    selector: 'BarFooHttpCaller',
    template: ´<child *ngIf="data.length > 0" [data]></child>´
})

class BarFooHttpCaller {
    private data: any;
    constructor(private foobar:Foobar) {
        this.data = {};
    }

    ngOnInit() {
        this.foobar.getCustomers().subscribe(() => {       
            console.log('httpdone') 
        });
        this.foobar.dataStream.subscribe((data) => {
            console.log('new data', data);
            this.data = data;
        })
    }
}
@组件({
选择器:“BarFooHttpCaller”,
模板:''
})
类BarFooHttpCaller{
私人资料:任何;
构造函数(专用foobar:foobar){
this.data={};
}
恩戈尼尼特(){
this.foobar.getCustomers().subscribe(()=>{
console.log('httpdone')
});
this.foobar.dataStream.subscribe((数据)=>{
console.log('新数据',数据);
这个数据=数据;
})
}
}
儿童:

import { Component, Input } from '@angular/core';

@Component({
    selector: 'child',
    template: ´<div>{{data}}</div>´
})

export class Child {
    @Input() data: any;

}
从'@angular/core'导入{Component,Input};
@组成部分({
选择器:'子',
模板:'{{data}}}'
})
导出类子类{
@输入()数据:任意;
}
1)您只需将下载的数据保存到您的服务中即可:

export class CustomersService {
  protected _customers: Array<Customer>;

  constructor(public http: Http) {}

  public getCustomers(): Observable<Array<Customer>> {
    return new Observable(observer => {
      if (this._customers) {
        observer.next(this._customers);
        return observer.complete();
      }
      this.http
        .get(this.baseURI + this.url)
        .map((r: Response) => (r.json() as Array<Customer>))
        .subscribe((customers: Array<Customer>) => {
          this._customers = customers;
          observer.next(this.customers);
          observer.complete();
        });
    });
  }
}
3) 利用
ReplaySubject

export class CustomersService {
  protected _customers$: ReplaySubject<Array<Customer>> = new ReplaySubject(1);
  protected _customersInitialized: boolean;

  constructor(public http: Http) {}

  public getCustomers(refresh?: boolean): Observable<Array<Customer>> {
    if (refresh || !this._customersInitialized) {
      this._customersInitialized = true;
      this.http
        .get(this.baseURI + this.url)
        .map((c: Response) => (c.json() as Array<Customer>))
        .subscribe((customers: Array<Customer>) => {
          this._customers$.next(customers);
        });
    }
    return this._customers$.asObservable().skip(+refresh).distinctUntilChanged();
  }
}
您还可以通过以下方式从
SomeService
公开始终最新的
customers
字段,以实现只读目的(如在模板中显示):

public get customers(): ReadonlyArray<Customer> {
  return this._customers;
}
public get customers():ReadonlyArray{
把这个还给你的客户;
}

如果希望多个子对象订阅同一个observable,但只执行observable一次,则可以执行以下操作

请注意,这确实符合可观察的设计,因为我们在服务层(observable.fromPromis(stream.toPromise())中执行可观察,而执行应该从组件subscribing.View获得更多信息

  //declare observable to listen to
  private dataObservable: Observable<any>;

  getData(slug: string): Observable<any> {

    //If observable does not exist/is not running create a new one
    if (!this.dataObservable) {

        let stream = this.http.get(slug + "/api/Endpoint")
            .map(this.extractData)
            .finally(() => {
                //Clear the observable now that it has been listened to
                this.staffDataObservable = null;
            });

        //Executes the http request immediately
        this.dataObservable = Observable.fromPromise(stream.toPromise());

    }        

    return this.staffDataObservable;
 }
//声明要侦听的可观察对象
私有数据可观察:可观察;
getData(slug:string):可观察{
//如果observable不存在/未运行,请创建一个新的
如果(!this.dataObservable){
让stream=this.http.get(slug+“/api/Endpoint”)
.map(此.extractData)
.最后(()=>{
//现在已经听过了,请清除可观察到的内容
this.staffDataObservable=null;
});
//立即执行http请求
this.dataObservable=Observable.fromPromise(stream.toPromise());
}        
返回this.staffDataObservable;
}

无需自定义实现。管道可以实现以下功能:

getCustomers$(): Observable<Customer> {
   return this.http
        .get<Customer>(this.baseURI + this.url)
        .pipe(shareReplay(1));               
}    
getCustomers$():可观察{
返回此文件。http
.get(this.baseURI+this.url)
.管道(1);
}    
我在这里做了几件事:

  • 添加
    shareReplay(1)
    pipe,确保请求只执行一次(只需回答问题)
  • 删除
    map
    并键入
    get
    调用
  • 带有
    $
    的后缀方法名称,表示返回了
    可观察的

  • 好的,但在这种情况下,我必须从调用getCustomers().subscribe(…)的组件开始。在我的应用程序中,我永远不知道首先访问哪个组件(一个用户可能输入另一个URL而不是另一个用户)。当我在服务本身中调用订阅时,它实际上不起作用。在这种情况下,我应该如何修改您的示例?您有多种可能性,将数据存储在数据流之外,并验证它是否已馈送,如果是,则返回数据流而不是http流。您还可以进行一次简单的去Bounce操作,以防止多次调用o getCustomers()因此,您可以避免处理并发性。另一种方法是在顶级路由组件中调用该方法,然后在child中订阅。只需稍加修改即可。您必须记住,在您的承诺中,只创建了一个可观察对象,而没有订阅。因此,您的解决方案仅在您订阅抄写此创建的observable并在订阅中调用“resolve…”。@David你是如何做到这一点的?我通常会做整个
    this.customers?Obs