Javascript multiple api fetches(youtube)

时间:2017-12-19 20:58:12

标签: javascript json api object youtube

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

首先我正在进行api调用以从特定通道获取所有视频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)

2 个答案:

答案 0 :(得分:0)

您可以创建自己的承诺,用作等待所有并行承诺返回的包装器,一旦它们全部成功返回,您可以resolve承诺,确认其成功完成或您的罐头reject承诺并在出现问题时提供错误回复。

请注意,实际工作是在函数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社区鼓励使用的非常棒的高阶函数。快乐的编码!

答案 1 :(得分:0)

杀死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.