asynchronous - 如何在 Angular2 循环/映射中执行异步 HTTP 请求并修改原始循环数组?

标签 asynchronous angular observable angular2-http

这里是 Angular2 的新手,想知道如何对数组模式执行此异步请求(不太确定模式名称)。

假设我使用 Angular2 的 Http获取包含 videoId 的 YouTube 播放列表在每个返回项目中。然后我需要用 videoId 遍历这个项目并向 YouTube 发出另一个请求以获取个人视频信息。这可以是另一个常见的 HTTP 请求,获取列表然后遍历列表并获取每个单独项目的详细信息。

let url = [YouTube API V3 list url]
let detailUrl = 'https://www.googleapis.com/youtube/v3/videos?part=contentDetails,statistics';

this.http.get(url)
    .map(res => res.json())
    .subscribe(data => {
        let newArray = data.items.map(entry => {

            let videoUrl = detailUrl + '&id=' + entry.id.videoId + 
                                       '&key=' + this.googleToken;

            this.http.get(videoUrl)
                .map(videoRes => videoRes.json())
                .subscribe(videoData => {
                     console.log(videoData);

                     //Here how to I join videoData into each item inside of data.items. 
                });
    });
});

所以上面的代码确实有效。但是我还有这两个问题:

  1. 如何加入 videoData返回data.items并确保 data.items 中的项目正确加入了正确的 videoData (使用 videoData 中相关项的 entry.id.videoIddata.items )并创建新的 newArray ?

  2. 我如何知道一切何时完成,并在所有异步请求完成后根据所有数据做某事?

  3. newArray 保持与第一个 HTTP 请求相同的顺序。作为第一个 HTTP,按 viewCount 排序访问 YouTube 搜索列表 API。像上面那样简单地嵌套 observable 不会保持原来的顺序。

更新

有了inoabrian solution,我就可以顺利的做到以上三点。但是当我再次调用 myvideoservice 时(比如将 url 更改为新的 NextPageToken),主题 - this._videoObject 有 2 个观察者。再次加载,它有 3 个观察者,依此类推。我需要一种方法来将主题重置为只有 1 个观察者,这样我就不会有重复的视频。这是清除/重置主题的最佳做法吗?

最佳答案

// You need to set up a subject in your sevice
private _videoObject = new Subject < any > ();
videoDataAnnounced$ = this._videoObject;


let url = [YouTube API V3 list url]
let detailUrl = 'https://www.googleapis.com/youtube/v3/videos?part=contentDetails,statistics';

this.http.get(url)
    .map(res => res.json())
    .subscribe(data => {
        this.cache = data.items;
        data.items.forEach(entry => {
            let videoUrl = detailUrl + '&id=' + entry.id.videoId + '&key=' + this.googleToken;
            this.http.get(videoUrl)
                .map(videoRes => videoRes.json())
                .subscribe(videoData => {
                    // This will announce that the full videoData is loaded to what ever component is listening.
                    this._videoObject.next(videoData);
                });
        });
    });



// In your constructor for your component you can subscribe to wait on the data being loaded.
public newVideos: any[] = [];
constructor(private myServiceToLoadVideos: myvideoservice) {
    let self = this;
    this.myServiceToLoadVideos.videoDataAnnounced$.subscribe((video) => {
        // Here you could loop through that
        self.myServiceToLoadVideos.cache.map(d => {
            if (d.id == video.id) {
                // Here you have the old data set without the details which is (d) from the cached data in the service.
                // And now you can create a new object with both sets of data with the video object
                d.snippet = video.items[0].snippet;
                d.statistics = video.items[0].statistics;
                d.contentDetails = video.items[0].contentDetails;
                this.posts = this.posts.concat(d);
            }
        });
        if(this.posts.length == this.cache.length){
          this.posts.sort(function(l,r){
            // if l is < r then it will return a negative number
            // else it will return a positive number.
            // That is how this sort function works
            return l.viewCount - r.viewCount;
          });

          // Here you will have all of the data and it will be sorted in order.
        }
    });
}

UPDATE -- -- --

The Subject is an observable - http: //reactivex.io/documentation/subject.html

    When you listen to the Subject it is not like q.all it will complete one by one until they complete.

The cache in the service call is just to keep track of the playlist.
Then when you receive the details in the constructor you can match them back up and keep order with the cache.

Q: "And when subscribe to the subject as in your code, the result is when ALL the "
next " in _videoObject finished, right?"
A: No, when each individual finishes you will get once at a time.

JS Sort - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

关于asynchronous - 如何在 Angular2 循环/映射中执行异步 HTTP 请求并修改原始循环数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38155110/

相关文章:

Python httpx 异步流数据?

java - 玩法2 异步Promise兑现

c# - 在已经拆分的上下文上调用 await 时是否有开销?

javascript - 在 angular2 应用程序中加载 JavaScript 文件

javascript - 我应该如何测试可观察对象抛出错误?

javascript - 如何从异步调用返回响应?

Angular 4 - 用户界面路由器

javascript - Angular 2、Node JS 和 Passport 问题

javascript - 类型 'campanha' 上不存在属性 'DisputaComponent[]' - Angular 2

android - 无法在 Kotlin Android 中的 Observable 上调用 from() 运算符