【问题标题】:Javascript multiple api fetches (youtube)Javascript 多个 api 获取 (youtube)
【发布时间】:2018-06-02 08:49:17
【问题描述】:

我正在尝试为 youtube 用户创建每个视频的观看次数的 json 对象。

首先,我进行 api 调用以获取来自特定频道的所有视频 ID,这些 ID 被推送到一个空数组。然后我遍历所有视频 ID,为每个视频进行多次 API 调用,以获取有关视图的数据。

现在每个视频都有自己的 API 调用,我似乎无法找到将所有调用中的所有数据合并到一个对象中的方法。

我确信这不是这样做的方法,这就是为什么我希望你们能推荐我一个更好的方法来解决这个问题。

谢谢!

var channelId = 'UCO1cgjhGzsSYb1rsB4bFe4Q'
var url = 'https://www.googleapis.com/youtube/v3/search?key=' + apiKey + '&channelId=' + channelId + '&part=snippet,id&order=date&maxResults=20'

fetch(url).then((resp) => resp.json()).then(function(data) {
        var videoIds = []
        for (var i = 0; i < data.items.length; i++) {
            videoIds.push(data.items[i].id.videoId)
        }
        return videoIds
    }).then(function(ids) {
        var urls = []
        for (var i = 0; i < ids.length; i++) {
            urls.push('https://www.googleapis.com/youtube/v3/videos?part=statistics&id=' + ids[i] + '&key=' + apiKey)
        }
        return urls
    }).then(function(urls) {
            for (var i = 0; i < urls.length; i++) {
                fetch(urls[i]).then((resp) => resp.json()).then(function(data) {
                    console.log(data)
                })
            }

更新

我设法通过使用另一个 fetch url 和 d3.json 函数来解决这个问题。

var search = 'https://www.googleapis.com/youtube/v3/search?key=' + apiKey + '&channelId=' + channelId + '&part=snippet,id&order=date&maxResults=5'

var videoIds = []

fetch(search).then((resp) => resp.json())
.then(function(data) {
    for (var i = 0; i < data.items.length; i++) {
        videoIds.push(data.items[i].id.videoId)
    }

    return fetch("https://www.googleapis.com/youtube/v3/videos?id=" +videoIds + "&part=snippet%2CcontentDetails%2Cstatistics&key=" + apiKey);

}).then(function(response) {
        d3.json(response.url, function(error, data) {
                    if (error) throw error;
                    console.log(data)

【问题讨论】:

  • 进展如何?我的回答有帮助吗?
  • @Matt 是的,谢谢,您的回答确实有帮助。只是返回的对象不包括每个单独视频的统计信息。现在我正在尝试各种方法来从这些提取中提取 statistics.viewCount 到一个组合对象中。您对此有什么建议吗?
  • 根据video 的API 参考,您应该能够使用以下点符号videoObj.statistics.viewCount 通过JSON 访问viewCount。这是截至 2017 年 12 月的当前文档的链接YouTube Video API Reference
  • 在查看了上面的请求之后,也许可以尝试从请求中删除part=statistics。我猜该请求应该返回完整的 video 对象,然后您可以按照上面列出的评论的方向进行操作。
  • 一切顺利吗?如果是这样,请投票/确认答案。如果没有,我很乐意帮助您解决这个问题。

标签: javascript json api object youtube


【解决方案1】:

Promise hell欢迎来到

ES2017 async/await 语法

把你的整个代码改成这样

async function foo() {
    var channelId = 'UCO1cgjhGzsSYb1rsB4bFe4Q'
    var url = `https://www.googleapis.com/youtube/v3/search?key=${apiKey}&channelId=${channelId}&part=snippet,id&order=date&maxResults=20`

    var resp = await fetch(url)
    var data = await resp.json()

    var videoIds = []
    for (var item of data.items)
        videoIds.push(item.id.videoId);

    var urls = []
    for (var id of videoIds)
        urls.push(`https://www.googleapis.com/youtube/v3/videos?part=statistics&id=${id}&key=${apiKey}`);

    for (var url of urls) { //This for loop will stop in each url to complete its fetch
        let resp = await fetch(url)
        let data = await resp.json()
        console.log(data)
    }
    return 'Good Anakin goooood'
} 

foo()
.then(msg => console.log(msg))
.catch(e => console.log(e)) //If some Error has been thrown or some fetch was rejected.

【讨论】:

    【解决方案2】:

    您可以创建自己的 Promise 用作包装器以等待所有并行 Promise 返回,一旦它们都成功返回,您可以 resolve 该 Promise,确认其成功完成或您可以 @987654322 @promise 并在出现问题时提供错误响应。

    请注意,真正的工作是在函数 getChannelVideos(channelId, config)... 更准确地说,在 Promise 主体内完成的:

    var channelId = 'UCO1cgjhGzsSYb1rsB4bFe4Q'
    
     + '&channelId='
    const baseUrl = 'https://www.googleapis.com/youtube/v3';
    let config = {
      apiKey: 'yourKeyHere',
      part: 'snippet,id',
      order: 'date',
      maxResults: 20
    }
    
    function queryArgs(config) {
      let query = '';
      config.apiKey ? query += '?key=' + config.apiKey : throw { err: 'You must provided an API KEY' };
      config.part ? query += '&part=' + config.part : query;
      config.order ? query += '&order=' + config.order : query;
      config.maxResults ? query += '&maxResults=' + config.maxResults : query;
      return query;
    }
    
    function getChannelVideos(channelId, config) {
     let URL = baseUrl + '/search' + queryArgs(config) + '&channelId=' + channelId;
     // We wrap everything we need to do in a Custom Promise, and return it for a .then(res => { // Success Handler }, err => { // Error Handler })
      return new Promise((resolve, reject) => {
        // videos to store data from each video request, videoPromises to wait on
        let videos = [];
        let videoPromises = [];
        // Make the Channel Request, followed by a request for each of its videos ( Callback hell)
        fetch(URL)
          .then((resp) => resp.json())
          .then(
            data => {
                // Declare vars outside map for improved memory management
                let currentVideoId;
                let currentRequestUrl;
                // iterate of the 'data.items' creating a new array of promises (.map(handler) returns a new array of whatever is returned from the handler)
                videoPromises = data.items.map(item => {
                  currentVideoId = item.id.videoId;
                  currentRequestUrl = baseUrl + '/videos?part=statistics&id=' + currentVideoId + '&key=' + config.apiKey;
                  return fetch(currentRequest)
                           .then(
                             res => {
                               // Push the Video Response to the videos array (You may want to select something more specific like 'res.data', but this depends on what data you want
                               videos.push(res);
                             }, 
                             err => {
                               console.log('Ut-oh - a Video request failed', err);
                             });
                });
            });
          // Wait for ALL the promises to succeed
          Promise.all(videoPromises).then(
            success => {
              console.log('It\'s all good! Everything was retrieved successfully!');
              resolve({
                status: 200,
                data: {
                  videos : videos
                }
              });
            },
            err => {
              reject({ 
                status: 500,
                error: err, 
                message: 'Whomp Whomp Whomp! Something didn\'t work, but the data has what did!', 
                data: videos 
              });
            })
      });
    }
    
    // NOW CALL IT
    getChannelVideos(channelId, config).then(
      res => {
        // here are the videos
        console.log('videos[]', res.data.videos);
      },
      err => {
        console.log('Darn, maybe next time', err);
      });
    

    您还应该看到性能提升,因为循环更少,调用堆栈上的更少。 Array.map(handler) 是 JavaScript 社区鼓励使用的一个非常棒的高阶函数。快乐编码!

    【讨论】:

    • 我通常使用lodash 库,所以我的地图功能可能需要稍微调整一下,但你应该明白要点。我还假设 fetch(url) 函数会根据您对 .then() 的使用返回一个承诺
    猜你喜欢
    • 2013-06-30
    • 2015-12-01
    • 2019-10-06
    • 2012-04-21
    • 1970-01-01
    • 2014-11-20
    • 2021-05-16
    • 2019-04-14
    • 2015-12-07
    相关资源
    最近更新 更多