我正在构建一个从YouTube获取视频数据的应用程序。
有这么多资源用于不同的解决方案,但在为服务订阅组件时,是否有一种方法被视为最佳实践?
这就是到目前为止我所拥有的:
// Component
export class LandingYoutubeComponent implements OnInit {
constructor(private youtube: YoutubeService) {
}
ngOnInit() {
this.youtube.getVideos().subscribe(data => console.log(data));
}
}
// Service
export class YoutubeService {
videoSubscription: Observable<any>;
API_KEY: string = 'someKey';
CHANNEL_ID: string = 'someID';
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.videoSubscription = this.http.get(this.configUrl); // create observable for external subscriptions
}
getVideos() {
return this.videoSubscription;
}
}
组件和服务都是相互抽象的,并粘贴了每个类封装的逻辑。
根据我从JS中了解到的情况,数组和对象是通过引用传递的,从技术上讲,这就是我在这里所做的,但这是正确的决定吗?
我只想知道这是否被认为是最好的做法,如果不是,我应该如何做?
谢谢!
我不会保留Observable
作为服务的属性;这与您提到的引用类型关系不大,而与Observable
s的总体设计关系更大。
你所做的并不一定是坏事;然而,Observable
是一个只有在订阅时才运行的合约。http.get
返回的Observable
是作为属性分配给您的服务的内容;如果从未订阅,则不会进行http调用。。。但是如果有三个组件订阅该Observable
,则将进行三个单独的http调用。
从HttpClient
返回的Observable
是冷的、有限的可观测的。这意味着它将发出一个单独的值,然后发送一个unsubscribe
信号。如果组件知道这一点,并且只需要一次数据,为什么不直接返回从http.get
创建的Observable
呢?这样,调用者可以在Observable
上使用任意数量的Observable
运算符,而不会影响试图获得相同值的任何其他组件。
将Observables
作为Services的属性(而不仅仅是在方法中返回新的(确实对某些事情有意义,但它们通常不是Observables
,而是Subjects
。这就是ngrx商店状态管理背后的全部设计理念。但对于冷的、有限的Observables
,只需将Observable
返回给调用者。
这就是我最终得到的解决方案:
// 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
。
因此,现在,想要订阅服务的组件现在订阅服务属性内的更改,而不是为每个新订阅构建一个新请求。