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

Getting data pushed to an array outside of a Promise

我正在使用 https://github.com/Haidy777/node-youtubeAPI-simplifier to grab some information from a playlist of Bounty Killers. The way, this library is setup seems to use Promise via Bluebird (https://github.com/petkaantonov/bluebird) which I don't know much about. Looking up the Beginner's Guide for BlueBird gives http://bluebirdjs.com/docs/beginners-guide.html 字面上只是显示

This article is partially or completely unfinished. You are welcome to create pull requests to help completing this article.

我可以设置库

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

以及列出赏金杀手的一些信息

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 数组,我不确定末尾的空数组是由于范围界定还是某些不同步导致 console.log(ytdata) 在 [=31 之前被调用=] 通话结束。

我如何才能将每个赏金杀手视频放入 ytdata 数组以供全球使用?

console.log(ytdata) 应该紧接在 FOR 循环之后。在承诺得到解决并且 FOR 循环执行完成之前,此数据不可用,并且尝试事先访问它会给你一个空数组。

(您当前的 console.log 不起作用,因为该代码在 promise 解决之前立即执行)。只有 THEN 块内的代码在 promise 被解析后执行。

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

你能在用户访问这个页面之前在幕后预先提出请求吗? (不确定这是个好主意,但确实是个主意)

您能否使用视频缩略图(就像 youtube 那样)以便在单击缩略图时开始流式传输和播放视频?

一些想法...希望对您有所帮助

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 []

console.log(ytdata) gets called before the API calls are finished

发现,这正是这里发生的事情,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+,它应该可以工作。