Repeated video duration values in asnyc to videoId

2019-09-19 19:44发布

问题:

I'm having a problem with the asynchronous methods that prints and returns all vidDuration values then viewCount values were placed for each videoId, but vidDuration repeated only the last value that was received and assigned it to all of the videoIds which is clearly wrong.

I tried setting up a temporary array called tempArray within the loop that store each of the vidDuration values which it did, then to print them to each vidDuration, but then again, it looped through the output however many values are in the array and duplicated the videos, which I don't want. I commented out lines involving tempArray and reverted back to the working problem.

From what I understand, the async methods printed all of the duration values without going to the output as if it got stuck there until it was done and resolved and then it looped the viewCount and output perfectly fine. I'm wondering how do I fix this in a programmatically logical way?

Script:

var channelName = 'ExampleChannel';
var vidWidth = 500;
var vidHeight = 400; 
var vidResults = 15; /* # of videos to show at once - max 50 */
var vidDuration = "";
var viewCount = 0;
var videoId = "";

$(document).ready(function() {
    $.get( // get channel name and load data
        "https://www.googleapis.com/youtube/v3/channels",
        {
            part: 'contentDetails',
            forUsername: channelName,
            key: 'XXXXXXXX'
        },

        function(data)
        {
            $.each(data.items, 
                function(i, item) {
                    console.log(item); // log all items to console
                    var playlistId = item.contentDetails.relatedPlaylists.uploads;
                    getPlaylists(playlistId);

            })
        }         
    );

    // function that gets the playlists
    function getPlaylists(playlistId)
    {
        $.get(
            "https://www.googleapis.com/youtube/v3/playlistItems",
            {
                part: 'snippet',
                maxResults: vidResults,
                playlistId: playlistId,
                key: 'XXXXXXXX'
            },

            // print the results
            function(data)
            {
                var output;
                /*var tempArray = new Array();*/ // temporary array for storing video duration values
                $.each(data.items, 
                    function(i, item) {
                        console.log(item);
                        var vidTitle = item.snippet.title; // video title
                        var vidDesc = item.snippet.description; // video description
                        var videoId = item.snippet.resourceId.videoId; // video id

                        // check if description is empty
                        if(vidDesc == null || vidDesc == "")
                        {
                            vidDesc = "No description was written."; // FIX: test msg to see where it still shows up
                            $('#desc').remove(); // remove video description
                        }
                        else vidDesc = item.snippet.description;

                        getVideoDuration(videoId).done(function(r){
                            vidDuration = r;
                            console.log(r);
                            /*tempArray[i] = r;*/ // store value into each array index
                            /*console.log("Array:", tempArray[i], tempArray);*/ // log to console
                            /*i++;*/ // increment


                        getViewCount(videoId).done(function(r){
                            viewCount = r;
                            console.log(r);

                        //vidDuration = getVideoDuration(videoId);
                        //viewCount = getViewCount(videoId);

                        // temp array index to loop thru array
                        /*$.each(tempArray, function(i){
                            vidDuration = tempArray[i]; // assign index value to vidDuration
                            console.log("In Each vidDuration: ", vidDuration);
                            i++;
                        });*/

                        console.log("id: " + videoId + " duration: " + vidDuration + " viewCount: " + viewCount); // return value in console

                        output = '<li><iframe height="' + vidHeight + '" width="' + vidWidth + '" src=\"//www.youtube.com/embed/' + videoId + '\"></iframe></li><div id="title">' + vidTitle + '</div><div id="desc">' + vidDesc + '</div><div id="duration">Length: ' + vidDuration + '</div><div id="stats">View Count: ' + viewCount + '</div>';

                        // Append results to list tag
                        $('#results').append(output);

                        }); // end of getVideoDuration(videoId).done
                    }); // end of getViewCount(videoId).done
                });
                /*console.log("TEMPARRAY[]",tempArray);*/ // print entire array
            }         
        );
    }

    // return video duration
    function getVideoDuration(videoId) 
    { 
        var defer1 = $.Deferred();
        var r = '';

        $.get(
            "https://www.googleapis.com/youtube/v3/videos",
            {
                part: 'contentDetails',
                id: videoId,
                key: 'XXXXXXXX',
            },

            function(data)
            {
                $.each(data.items,
                    function(i, item) {
                        r = item.contentDetails.duration;
                        defer1.resolve(r);
                        console.log("in vidDuration func", r);
                    });
            }
        );
        return defer1.promise();

    }

    // return video view count
    function getViewCount(videoId) 
    { 
        var defer2 = $.Deferred();
        var r = '';

        $.get(
            "https://www.googleapis.com/youtube/v3/videos",
            {
                part: 'contentDetails, statistics',
                id: videoId,
                key: 'XXXXXXXX',
            },

            function(data)
            {
                $.each(data.items,
                    function(i, item) {
                        r = item.statistics.viewCount;
                        defer2.resolve(r);
                        console.log("in viewCount func", r);
                    });  
            }
        );
        return defer2.promise();
    }
});

Screenshot results (normal refresh):

Screenshot results (using debugger):

Here's a screenshot of the results when stepping through with the debugger console. (Why are the results different from when the page normally loads? Is this typical action of the async methods? How do I fix this?)

回答1:

In fact the second promise is misplaced, the second promise is resolved AFTER that all the promises from the first promise have been resolved, so the last value is save. logical

Now if you resolve the first promise WHEN second is resolved one by one you are able to correct the problem.

var view = 0;
r = item.contentDetails.duration; // video duration 
getViewCount(videoId).done(function(t){
        view = t;
        dfrd1.resolve(r, view);
});

Check the screenshot:

I change a bit the code to solve the problem.

var channelName = 'example';
var vidWidth = 500;
var vidHeight = 400; 
var vidResults = 15; /* # of videos to show at once - max 50 */
var vidDuration = "";
var viewCount = 0;
var videoId = "";

$(document).ready(function() {
    $.get( // get channel name and load data
        "https://www.googleapis.com/youtube/v3/channels",
        {
            part: 'contentDetails',
            forUsername: channelName,
            key: 'xxx'
        },

        function(data)
        {
            $.each(data.items, 
                function(i, item) {
                    //console.log(item); // log all items to console
                    var playlistId = item.contentDetails.relatedPlaylists.uploads;
                    //var viewCount = console.log(item.statistics.viewCount);
                    getPlaylists(playlistId);

            });
        }         
    );

    // function that gets the playlists
    function getPlaylists(playlistId)
    {
        $.get(
            "https://www.googleapis.com/youtube/v3/playlistItems",
            {
                part: 'snippet',
                maxResults: vidResults,
                playlistId: playlistId,
                key: 'xxx'
            },

            // print the results
            function(data)
            {
                var output;
                $.each(data.items, 
                    function(i, item) {
                        console.log(item);
                        var vidTitle = item.snippet.title; // video title
                        var vidDesc = item.snippet.description; // video description
                        var videoId = item.snippet.resourceId.videoId; // video id

                        // check if description is empty
                        if(vidDesc == null || vidDesc == "")
                        {
                            vidDesc = "No description was written."; // FIX: test msg to see where it still shows up
                            $('#desc').remove(); // remove video description
                        }
                        else vidDesc = item.snippet.description;

                        getVideoDuration(videoId).done(function(d, v){
                             vidDuration = d;
                             //console.log(r);


                               viewCount = v;

                        document.write("id: " + videoId + " duration: " + vidDuration + " viewCount: " + viewCount); // return value in console

                        document.write("<br>");

                        output = '<li><iframe height="' + vidHeight + '" width="' + vidWidth + '" src=\"//www.youtube.com/embed/' + videoId + '\"></iframe></li><div id="title">' + vidTitle + '</div><div id="desc">' + vidDesc + '</div><div id="duration">Length: ' + vidDuration + '</div><div id="stats">View Count: ' + viewCount + '</div>';

                    // Append results to list tag
                    $('#results').append(output);
                   });
                });
            }         
        );
    }

    // return video duration
    function getVideoDuration(videoId) 
    { 
        var dfrd1 = $.Deferred();
        var r = '';
        $.get(
            "https://www.googleapis.com/youtube/v3/videos",
            {
                part: 'contentDetails',
                id: videoId,
                key: 'xxx',
            },

            function(data)
            {
                $.each(data.items,
                    function(i, item) {
                        //videoId = item.snippet.resourceId.videoId;
                        var view = 0;
                        r = item.contentDetails.duration; // video duration 
                        getViewCount(videoId).done(function(t){
                          view = t;
                          dfrd1.resolve(r, view);
                        });

                        //alert(videoId);
                    });    
            }
        );
        return dfrd1.promise();
    }

    // return video view count
    function getViewCount(videoId) 
    { 
        var dfrd2 = $.Deferred();
        var r = '';
        $.get(
            "https://www.googleapis.com/youtube/v3/videos",
            {
                part: 'contentDetails, statistics',
                id: videoId,
                key: 'xxx',
            },

            function(data)
            {

                $.each(data.items,
                    function(i, item) {
                        //videoId = item.snippet.resourceId.videoId;

                        r = item.statistics.viewCount; // view count
                        //alert(videoId);
                        dfrd2.resolve(r);

                      // console.log("in", r);
                    });  
            }
        );
        return dfrd2.promise();
    } 
});