将数据推送到Promise之外的数组

时间:2016-01-04 17:44:32

标签: node.js youtube promise bluebird

我正在使用https://github.com/Haidy777/node-youtubeAPI-simplifier从Bounty Killers的播放列表中获取一些信息。方式,这个库设置似乎使用Promise via Bluebird(https://github.com/petkaantonov/bluebird),我不太了解。查看BlueBird的初学者指南,提供http://bluebirdjs.com/docs/beginners-guide.html字面上只显示

  

本文部分或完全未完成。欢迎您创建拉取请求以帮助完成本文。

我可以设置库

var ytapi = require('node-youtubeapi-simplifier');
ytapi.setup('My Server Key');

除了列出有关Bounty Killers的一些信息

ytdata = [];

ytapi.playlistFunctions.getVideosForPlaylist('PLCCB0BFBF2BB4AB1D')
     .then(function (data) {
         for (var i = 0, len = data.length; i < len; i++) {
             ytapi.videoFunctions.getDetailsForVideoIds([data[i].videoId])
                  .then(function (video) {
                      console.log(video);
                      // ytdata.push(video); <- Push a Bounty Killer Video
             });
          }
});

// console.log(ytdata); This gives []

基本上上面提取了完整的播放列表(通常这里会有一些分页,具体取决于长度)然后,getVideosForPlaylist的数据会迭代列表并为每个YouTube视频调用getDetailsForVideoIds。一切都很好。

从中获取数据会产生问题。我想将视频对象推送到ytdata数组,我不确定最后的空数组是由于作用域还是某些不同步,因此在API调用之前调用console.log(ytdata)结束。

我如何才能将每个赏金杀手视频纳入ytdata数组,以便在全球推出?

3 个答案:

答案 0 :(得分:2)

  

在API调用完成之前调用console.log(ytdata)

当然,这就是这里发生的事情,API调用是异步的。一旦您使用异步功能,如果要处理返回的数据,则必须采用异步方式。您的代码可以这样写:

var ytapi = require('node-youtubeapi-simplifier');
ytapi.setup('My Server Key');

// this function return a promise you can "wait"
function getVideos() {
    return ytapi.playlistFunctions
        .getVideosForPlaylist('PLCCB0BFBF2BB4AB1D')
        .then(function (videos) {
            // extract all videoIds
            var videoIds = videos.map(video => video.videoId);

            // getDetailsForVideoIds is called with an array of videoIds
            // and return a promise, one API call is enough
            return ytapi.videoFunctions.getDetailsForVideoIds(videoIds);
        });
}

getVideos().then(function (ydata) {
    // this is the only place ydata is full of data
    console.log(ydata);
});

我在videos.map(video => video.videoId);中使用了ES6的箭头功能,如果你的nodejs是v4 +,它应该可以使用。

答案 1 :(得分:1)

console.log(ytdata)应该在FOR循环之后立即执行。在解析promise并且FOR循环执行完成并且尝试预先访问它之前,这些数据不可用,这将为您提供一个空数组。

(您当前的console.log无法正常工作,因为该代码是在解析承诺之前立即执行的)。只有在解决了承诺后才执行THEN块内的代码。

如果你现在或者需要现有的数据,并且对视频的请求需要很长时间,那么你可以一次或根据需要或在一个单独的线程(可能使用网络工程师)请求1个视频吗?你能实现缓存吗?

在用户访问此页面之前,您是否可以在幕后提出请求? (不确定这是一个好主意,但这是一个想法)

您是否可以使用视频缩略图(例如youtube),以便在点击缩略图时开始播放和播放视频?

一些想法......希望这会有所帮助

答案 2 :(得分:1)

ytdata = [];

ytapi.playlistFunctions.getVideosForPlaylist('PLCCB0BFBF2BB4AB1D')
     .then(function (data) {
         // THE CODE INSIDE THIS THEN BLOCK IS EXECUTED WHEN ALL THE VIDEO IDS HAVE BEEN RETRIEVED AND ARE AVAILABLE
         // YOU COULD SAVE THESE TO A DATASTORE IF YOU WANT

         for (var i = 0, len = data.length; i < len; i++) {
             var videoIds = [data[i].videoId];
            ytapi.videoFunctions.getDetailsForVideoIds(videoIds)
                  .then(function (video) {
                      // THE CODE INSIDE THIS THEN BLOCK IS EXECUTED WHEN ALL THE DETAILS HAVE BEEN DOWNLOADED FOR ALL videoIds provided
                      // AGAIN YOU CAN DO WHATEVER YOU WANT WITH THESE DETAILS
                      // ALSO NOW THAT THE DATA IS AVAILABLE YOU MIGHT WANT TO HIDE THE LOADING ICON AND RENDER THE PAGE! AGAIN JUST AN IDEA, A DATA STORE WOULD PROVIDE FASTER ACCESS BUT YOU WOULD NEED TO UPDATE THE CACHE EVERY SO OFTEN
                      // ytdata.push(video); <- Push a Bounty Killer Video
             });
             // THE DETAILS FOR ANOTHER VIDEO BECOMES AVAILABLE AFTER EACH ITERATION OF THE FOR LOOP
          }
          // ALL THE DATA IS AVAILABLE WHEN THE FOR LOOP HAS COMPLETED
});

// This is executed immediately before YTAPI has responded.
// console.log(ytdata); This gives []