如何等到所有异步调用完成

How to wait until all async calls are finished

我有 NestJS 应用程序,它与 YoutubeAPI 交互并从中加载视频。 一种特定的方法很重要,它是下面的 loadVideos。方法它自己内部有多个异步,我需要在一切完成后使用 videoIdMap 属性

private loadVideos(
    playListId: string,
    channel: Channel,
    nextPageToken: string,
    stopLoadingOnVideoId: string,
  ) {
    const baseUrl = YoutubeService.VIDEO_URL_SNIPPET_BY_ID + playListId;
    const response = this.httpService
      .get(nextPageToken ? baseUrl + '&pageToken=' + nextPageToken : baseUrl)
      .pipe(map((response) => response.data));
    response.subscribe((data) => {
      data.items.forEach((item) => {
        if (stopLoadingOnVideoId && item.snippet.resourceId.videoId === stopLoadingOnVideoId) {
          return;
        }        
        this.prepareVideoEntity(item.snippet, channel).then((partialVideo) =>              
          this.videoService.create(partialVideo).then((video) => {     
            this.videoIdMap[video.youtubeId] = video.id;
          }),
        );
      });      
      if (data.nextPageToken) {        
        this.loadVideos(
          playListId,
          channel,
          data.nextPageToken,
          stopLoadingOnVideoId,
        );
      }
    });
  }

对我来说理想的解决方案是以某种方式使 loadVideos 异步,这样我以后可以做:

public methodWhichCallLoadVideos(): void {
  await loadVideos(playListId, channel, null, stopLoadingOnVideoId)
  // My code which have to be executed right after videos are loaded
}

我尝试过的每个解决方案都以 this.videoIdMap 为空对象或存在编译问题而告终,因此欢迎任何想法。

您可以切换到 promises 而不是 Observables,从而将方法变成异步方法,只要 data 有一个 nextPageToken:

private async loadVideos(
        playListId: string,
        channel: Channel,
        nextPageToken: string,
        stopLoadingOnVideoId: string,
    ) {
        const baseUrl = YoutubeService.VIDEO_URL_SNIPPET_BY_ID + playListId;
        const response = await this.httpService
            .get(nextPageToken ? url + '&pageToken=' + nextPageToken : url).toPromise();
        const { data } = response;
        for (const item of data.items) {
            if (stopLoadingOnVideoId && item.snippet.resourceId.videoId === stopLoadingOnVideoId) {
                continue;
            }
            const partialVideo = await this.prepareVideoEntity(item.snippet, channel);
            const video = await this.videoService.create(partialVideo)
            this.videoIdMap[video.youtubeId] = video.id;
        }
        if (data.nextPageToken) {
            await this.loadVideos(
                playListId,
                channel,
                data.nextPageToken,
                stopLoadingOnVideoId,
            );
        }
    }

在你的来电者中你可以简单地等待 loadVideos(...):

private async initVideoIdMap(...) {
  await this.loadVideos(...);
  // this.videoIdMap should be correctly populated at this point
}