YouTube的异步功能 [英] YouTube Asynchronous function

查看:117
本文介绍了YouTube的异步功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近一直在搞乱使用YouTube API的Javascript,但我碰到的一个问题(总是如!)。

我需要一个函数返回的信息的数组有关视频:

  [0:标题,1:说明2:发布日期,3:缩略图URL]

该函数将ID的视频,然后做了video.list具有该ID。下面是该函数:

 函数getVidInfo(VidId){
    VAR vidRequest;
    VAR vidRequestResponse;
    VAR returnArray =新阵列(4);    vidRequest = gapi.client.youtube.videos.list({
        部分:'片断',
        ID:VidId
    });
    vidRequest.execute(功能(响应){
        如果(response.pageInfo.totalResults!= 0){
            returnArray [0] = response.result.items [0] .snippet.title;
            returnArray [1] = response.result.items [0] .snippet.description;
            returnArray [2] = response.result.items [0] .snippet.publishedAt;
            //检查HD缩略图
            如果(response.result.items [0] .snippet.thumbnails.maxres.url){
                returnArray [3] = response.result.items [0] .snippet.thumbnails.maxres.url
            }
            其他{
                returnArray [3] = response.result.items [0] .snippet.thumbnails.standard.url;
            }
            的console.log(returnArray); //将记录所需的返回数组
        }
    });
    返回returnArray; //不返回所需的阵列
}

你可以从阵列被设置正确但它不返回该值的注释中看到。

我有什么企图?


  • 使用外部变量从一个名为 vidRequest.execute功能被设置()

  • vidRequest.execute返回()

  • 把响应转换成一个变量,然后分配阵列(给了我一个错误约pageInfo是未定义

备注


  • 这似乎是一个异步的问题

  • 我需要保持 getVidInfo()

  • 这definetely被调用时,谷歌API负荷

  • 这似乎在初始加载工作,但刷新打破它

  • 所有信息都记录到控制台此刻

展开code

index.html的

 <!DOCTYPE HTML>
< HTML和GT;
< HEAD>
    <标题> YT测试与LT; /标题>
    <! - 我的脚本 - >
    &所述; SCRIPT SRC =test.js>&下; /脚本>
< /头><身体GT;
    <! - 负载谷歌API的最后一个 - >
    &所述; SCRIPT SRC =htt​​ps://apis.google.com/js/client.js?onload=googleApiClientReady> < / SCRIPT>
< /身体GT;
< / HTML>

test.js

  VAR apiKey =[您的API密钥]; //我没有将其设置为我的API密钥
VAR latestVidUrl;
VAR请求;
VAR vidId;
VAR vidInfo;功能googleApiClientReady(){
    的console.log(谷歌API装);
    gapi.client.setApiKey(apiKey);
    gapi.client.load('YouTube的','V3',函数(){
        请求= gapi.client.youtube.search.list({
            部分:'ID',
            的channelID:UCOYWgypDktXdb-HfZnSMK6A',
            的maxResults:1,
            类型:视频,
            订购日期'
        });
        request.execute(功能(响应){
            如果(response.pageInfo.totalResults!= 0){
                vidId = response.result.items [0] .id.videoId;
                //console.log(vidId);
                vidInfo = getVidInfo(vidId);
                的console.log(vidInfo);
            }
        });
    });
}功能getEmbed code(ID){
    VAR BASEURL =htt​​p://www.youtube.com/watch?v=
    返回BASEURL + id.toString();
}功能getVidInfo(VidId){
    VAR vidRequest;
    VAR vidRequestResponse;
    VAR returnArray =新阵列(4);    vidRequest = gapi.client.youtube.videos.list({
        部分:'片断',
        ID:VidId
    });
    vidRequest.execute(功能(响应){
        如果(response.pageInfo.totalResults!= 0){
            returnArray [0] = response.result.items [0] .snippet.title;
            returnArray [1] = response.result.items [0] .snippet.description;
            returnArray [2] = response.result.items [0] .snippet.publishedAt;
            //检查HD缩略图
            如果(response.result.items [0] .snippet.thumbnails.maxres.url){
                returnArray [3] = response.result.items [0] .snippet.thumbnails.maxres.url
            }
            其他{
                returnArray [3] = response.result.items [0] .snippet.thumbnails.standard.url;
            }
            的console.log(returnArray); //将记录所需的返回数组
        }
    });
    返回returnArray; //不返回所需的阵列
}


解决方案

执行函数是异步的;因此,它不是由你返回 returnArray 数组的时间内完成,所以空数组被送回,而不是(如果你有控制台打开,你会看到这其中的空数组回来并且得到记录,然后在回调发生的第二次左右后记录)的情况下,。这是在异步编程的最大障碍之一,并与YouTube的API它曾经是它周围的唯一方法是窝在多个级别的回调(即没有它作为一个单独的函数返回一个值) - 或者我喜欢亲切地长期回调开始。所以,你可以走这条路(你来自哪里,你的 getVidInfo 功能将所有code成从那里你得到的ID请求的回调),但将得到非常凌乱......幸运的是API客户,最近推出的功能,使解决这一问题变得很简单 - 在客户端GAPI现在的承诺/ A +标准

所以基本上,所有的请求对象现在可以返回一个无极的对象,而不是利用回调函数,所以他们都得到处理,并在你需要他们的顺序解决,您可以把它们连在一起(注意,这个承诺对象不非常轻微改变应答包,其中的参数,如 pageInfo 结果的儿童的JSON结构属性,而不是兄弟姐妹 - 你会在code样本见下文明白我的意思)。这也将大大简化您的code,所以你可以做这样的事情:

  VAR apiKey =[您的API密钥];功能googleApiClientReady(){
    的console.log(谷歌API装);
    gapi.client.setApiKey(apiKey);
    gapi.client.load('YouTube的','V3',函数(){
        VAR请求= gapi.client.youtube.search.list({
            部分:'ID',
            的channelID:UCOYWgypDktXdb-HfZnSMK6A',
            的maxResults:1,
            类型:视频,
            订购日期'
        })。然后(功能(响应){
            如果(response.result.pageInfo.totalResults!= 0){//注意pageInfo现在怎么是response.result的孩子......这是因为承诺对象的结构不同位
                返回response.result.items [0] .id.videoId;
            }
        }),然后(功能(vidId){
                返回gapi.client.youtube.videos.list({
                        部分:'片断',
                        ID:vidId
                });
        })。然后(功能(响应){
                VAR returnArray =阵列();
                如果(response.result.pageInfo.totalResults!= 0){
                        returnArray [0] = response.result.items [0] .snippet.title;
                        returnArray [1] = response.result.items [0] .snippet.description;
                        returnArray [2] = response.result.items [0] .snippet.publishedAt;
                        //检查HD缩略图
                        如果(response.result.items [0] .snippet.thumbnails.maxres.url){
                                returnArray [3] = response.result.items [0] .snippet.thumbnails.maxres.url;
                        }
                        其他{
                                returnArray [3] = response.result.items [0] .snippet.thumbnails.standard.url;
                        }
                }
                返回returnArray;
        }),然后(功能(returnArray){
                的console.log(returnArray);
        });
  });
}

此架构也大大错误处理帮助,因为你可以构建更多的匿名函数传递在每个第二参数然后呼吁要执行时,API抛出某种类型的错误。由于每个呼叫的返回一个承诺,你可以在最后调用,使用 returnArray 但是你需要,它会等待,直到所有的作品都在执行前得到解决。

I've been messing with the YouTube Javascript API recently, but I've run into a problem (as always!).

I need a function to return an array of information about a video:

 [0: Title, 1: Description, 2: Publish Date, 3: Thumbnail URL]

The function takes the id of a video then does a video.list with that id. Here is that function:

function getVidInfo(VidId){
    var vidRequest;
    var vidRequestResponse;
    var returnArray = new Array(4);

    vidRequest = gapi.client.youtube.videos.list({
        part: 'snippet',
        id: VidId
    });
    vidRequest.execute(function(response){
        if(response.pageInfo.totalResults != 0) {
            returnArray[0] = response.result.items[0].snippet.title;
            returnArray[1] = response.result.items[0].snippet.description;
            returnArray[2] = response.result.items[0].snippet.publishedAt;
            //Check for HD thumbnail
            if (response.result.items[0].snippet.thumbnails.maxres.url){
                returnArray[3] = response.result.items[0].snippet.thumbnails.maxres.url
            }
            else {
                returnArray[3] = response.result.items[0].snippet.thumbnails.standard.url;
            }
            console.log(returnArray); //Will log desired return array
        }
    });
    return returnArray; //Not returning desired array
}

As you can see from the comments the array is being set correctly however it's not returning that value.

What have I tried?

  • Using an external variable being set from a function called in vidRequest.execute()
  • Returning from vidRequest.execute()
  • Putting response into a variable and then assigning the array (Gave me an error about pageInfo being undefined)

Notes

  • It appears to be an asynchronous problem
  • I need to keep getVidInfo()
  • It definetely gets called when the Google API loads
  • It appears to work on the initial load, but a refresh breaks it
  • All info is logged to the console at the moment

Full Code

index.html

<!DOCTYPE html>
<html>
<head>
    <title>YT Test</title>
    <!--My Scripts-->
    <script src="test.js"></script>
</head>

<body>
    <!-- Load google api last-->
    <script src="https://apis.google.com/js/client.js?onload=googleApiClientReady"> </script>
</body>
</html>

test.js

var apiKey = "[YOUR API KEY]"; //I did set this to my API key
var latestVidUrl;
var request;
var vidId;
var vidInfo;

function googleApiClientReady() {
    console.log("Google api loaded");
    gapi.client.setApiKey(apiKey);
    gapi.client.load('youtube', 'v3', function() {
        request = gapi.client.youtube.search.list({
            part: 'id',
            channelId: 'UCOYWgypDktXdb-HfZnSMK6A',
            maxResults: 1,
            type: 'video',
            order: 'date'
        });
        request.execute(function(response) {
            if(response.pageInfo.totalResults != 0) {
                vidId = response.result.items[0].id.videoId;
                //console.log(vidId);
                vidInfo = getVidInfo(vidId);
                console.log(vidInfo);
            }
        });
    }); 
}

function getEmbedCode(id){
    var baseURL = "http://www.youtube.com/watch?v="
    return baseURL + id.toString();
}

function getVidInfo(VidId){
    var vidRequest;
    var vidRequestResponse;
    var returnArray = new Array(4);

    vidRequest = gapi.client.youtube.videos.list({
        part: 'snippet',
        id: VidId
    });
    vidRequest.execute(function(response){
        if(response.pageInfo.totalResults != 0) {
            returnArray[0] = response.result.items[0].snippet.title;
            returnArray[1] = response.result.items[0].snippet.description;
            returnArray[2] = response.result.items[0].snippet.publishedAt;
            //Check for HD thumbnail
            if (response.result.items[0].snippet.thumbnails.maxres.url){
                returnArray[3] = response.result.items[0].snippet.thumbnails.maxres.url
            }
            else {
                returnArray[3] = response.result.items[0].snippet.thumbnails.standard.url;
            }
            console.log(returnArray); //Will log desired return array
        }
    });
    return returnArray; //Not returning desired array
}

解决方案

The execute function is asynchronous; thus, it hasn't completed by the time you're returning the returnArray array, and so an empty array gets sent back instead (if you have the console open you'll see that's the case, where the empty array comes back and gets logged, and then a second or so later the logging within the callback happens). This is one of the biggest obstacles in asynchronous programming, and with the YouTube APIs it used to be that the only way around it was to nest your callbacks in multiple levels (i.e. don't have it as a separate function that returns a value) -- or what I like to affectionately term callback inception. So you could go that route (where you move all the code from your getVidInfo function up into the callback from the request where you get the ID), but that will get very messy ... and luckily the API client very recently introduced features that make solving this problem a whole lot easier -- the gapi client is now Promises/A+ compliant.

So basically, all request objects can now return a Promise object instead of utilize a callback function, and you can chain them all together so they all get processed and resolved in the order you need them to (note that this promise object does very slightly change the json structure of the response packet, where parameters such as pageInfo are children of the result attribute rather than siblings -- you'll see in the sample code below what I mean). This will also greatly simplify your code, so you could do something like this:

var apiKey = "[YOUR API KEY]";  

function googleApiClientReady() {
    console.log("Google api loaded");
    gapi.client.setApiKey(apiKey);
    gapi.client.load('youtube', 'v3', function() {
        var request = gapi.client.youtube.search.list({
            part: 'id',
            channelId: 'UCOYWgypDktXdb-HfZnSMK6A',
            maxResults: 1,
            type: 'video',
            order: 'date'
        }).then(function(response) {
            if(response.result.pageInfo.totalResults != 0) { // note how pageInfo is now a child of response.result ... this is because the promise object is structured a bit differently
                return response.result.items[0].id.videoId;
            }
        }).then(function(vidId) {
                return gapi.client.youtube.videos.list({
                        part: 'snippet',
                        id: vidId
                });
        }).then(function(response) { 
                var returnArray=Array();
                if(response.result.pageInfo.totalResults != 0) {
                        returnArray[0] = response.result.items[0].snippet.title;
                        returnArray[1] = response.result.items[0].snippet.description;
                        returnArray[2] = response.result.items[0].snippet.publishedAt;
                        //Check for HD thumbnail
                        if (response.result.items[0].snippet.thumbnails.maxres.url){
                                returnArray[3] = response.result.items[0].snippet.thumbnails.maxres.url;
                        }
                        else {
                                returnArray[3] = response.result.items[0].snippet.thumbnails.standard.url;
                        }
                }
                return returnArray;
        }).then(function(returnArray) {
                console.log(returnArray);
        });
  });
}

This architecture could also greatly help with error handling, as you could construct additional anonymous functions to pass as the 2nd argument in each then call to be executed when the API throws an error of some sort. Because each of the calls returns a promise, you can, in the final call, use returnArray however you need, and it will wait until all the pieces are resolved before executing.

这篇关于YouTube的异步功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆