向服务的可观察性订购组件时的最佳实践是什么? [Angular 2+]

时间:2018-12-10 20:52:07

标签: angular asynchronous angular-services angular-components angular-observable

我正在构建一个可从YouTube抓取视频数据的应用程序。

用于不同解决方案的资源太多,但是在向服务订购组件时是否有一种被认为是最佳实践的方法?

到目前为止,这是我所拥有的:

const dataObject = {firstName: "Mike", employeeId: "1020"};
const newArray = Object.entries(dataObject).map(([property, value]) => ({
  operator: 'sum',
  value,
  property,
  type: typeof value
}));
console.log(newArray);

组件和服务都是彼此抽象的,并粘贴了每个类封装的逻辑。

从JS得知,数组和对象都是通过引用传递的,这在技术上是我在这里所做的事情,但这是正确的决定吗?

我只想知道是否认为这样做是最佳做法,如果不是,我应该如何去做?

谢谢!

2 个答案:

答案 0 :(得分:1)

我不会将Observable保留为服务的属性;一般而言,这与您提到的引用类型无关,而与Observable的设计更多有关。

您所做的不一定坏;但是,Observable是仅在订阅时运行的合同。 Observable返回的http.get是作为属性分配给您的服务的;如果从未订阅过,则不会进行任何HTTP调用...但是,如果三个组件订阅了该Observable,则将进行三个单独的http调用。

Observable返回的HttpClient是有限的,可观察的冷信号。这意味着它将发出一个单一值,然后发送unsubscribe信号。如果组件知道这一点并且只想要一次数据,为什么不直接返回从Observable创建的http.get?这样,调用方就可以在Observable上使用任意数量的Observable运算符,而不会影响试图获得相同值的任何其他组件。

Observables作为Services的属性(而不是仅在方法中返回新的元素)确实对某些事情有意义,但通常不是Observables Subjects。这就是ngrx-store的状态管理背后的整个设计理念。但是对于有限的Observables来说,只需将Observable返回给调用方即可。

答案 1 :(得分:0)

这是我最终得到的解决方案:

// Component
export class LandingYoutubeComponent implements OnInit, OnDestroy {

  videos: any[];

  constructor(private youtube: YoutubeService) { }

  ngOnInit() {
    //  change videos array for every change in service.
    this.youtube.getVideoSubject().subscribe(([v1, v2, v3, v4]: any[]) => {
      this.videos = v1 && v2 && v3 && v4 ? [v1, v2, v3, v4] : [];
      console.log(this.videos);
    });
  }

  ngOnDestroy() {
    this.youtube.getVideoSubject().unsubscribe();
  }
}

// Service
export class YoutubeService {

  private videos: any[];
  private videoSubject: BehaviorSubject<any>;
  private API_KEY: string = 'someKey';
  private CHANNEL_ID: string = 'someId';
  private configUrl: string = `https://www.googleapis.com/youtube/v3/search?part=snippet&channelId=${this.CHANNEL_ID}&maxResults=50&order=date&type=video&key=${this.API_KEY}`

  constructor(private http: HttpClient) {
    this.videos = [];
    this.videoSubject = new BehaviorSubject<any[]>(this.videos);
    this.http.get(this.configUrl).subscribe((videos: any) => {
      this.videos = videos.items;
      this.videoSubject.next(this.videos.slice());  //  emit videos for all subscriptions
    });
  }

  getVideoSubject(): BehaviorSubject<any[]> {
    return this.videoSubject; //  return reference to BehaviorSubject
  }
}

@joh04667所述,先前的解决方案针对对初始解决方案的服务进行的每个订阅都建立了一个新的http请求。因此,为了减少发出的http请求,尽管有多个订阅,我也想通过仅创建一个请求来填充服务属性。我也将Observable更改为继承的类BehaviorSubject

现在,想要订阅服务的组件现在可以订阅服务属性内的更改,而不必为每个新订阅建立新的请求。