0

I am definitely not seeing this straight so am looking for a quick hand. I've been googling about and not found much that has helped.

Set the scene:

I have a node app that uses the 'googleapis' package. Now, I have that working fine and returning data (mostly) as expected.

The problem comes when I have to make a separate call to get the duration for each video (only way to get that bit of data is with a separate call).

I don't seem to be able to pass the duration value up the scope. I know I'm not doing it right and need to do it different but I just can't see the wood for the trees here.

youtubeClient.search.list({ part: 'id,snippet', maxResults: 10, q: searchTerm, type: 'video' }, 
        function (err, data) {
            if (err) {
                console.error('Error: ' + err);
            }

            if (data) {
                var returnList = [];

                for (var item in data.items) {

                    var duration = '00:00'; // THIS IS THE VARIABLE I WANT POPULATED
                    var value = data.items[item].id.videoId;

                    youtubeClient.videos.list({ part: 'contentDetails', id: data.items[item].id.videoId }, 
                        function (err, details) {
                            if (err) {
                                console.error('Error: ' + err);
                            }

                            if (details) {
                                // THIS IS WHERE I AM TRYING TO SET THE DURATION FIELD FROM THE RESULT
                                duration = details.items[0].contentDetails.duration;
                            }
                    });

                    returnList.push({value: value, duration: duration});

                }

                res.json(returnList);
            }
        });

As you can see, what I am trying to achieve shouldn't be at all difficult so any help would be appreciated. Thank you.

Roooss
  • 626
  • 1
  • 9
  • 24
  • 1
    This is a classic ***async operation inside a loop problem***. The loop runs to completion before even the first async operation finishes and calls its callback, messing up the timing of everything. Suggest you do some searches to understand more about why your code doesn't work. Unfortunately, I don't think there's a good canonical answer that can be used as a reference for all of these types of questions. – jfriend00 May 30 '16 at 02:03
  • 1
    https://www.npmjs.com/package/async – afuous May 30 '16 at 02:04
  • I had a feeling that would be exactly the case jfriend00. that is a shame, I will look in to it a bit more – Roooss May 30 '16 at 02:09
  • You can start here:[How to return value from asynchronous call](http://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call). – jfriend00 May 30 '16 at 02:46
  • And, also this one from earlier today: [For loop in redis with nodejs asynchronous requests](http://stackoverflow.com/questions/37514709/for-loop-in-redis-with-nodejs-asynchronous-requests/37514794#37514794) and [program fails because readFile is asynchronous?](http://stackoverflow.com/questions/37500766/program-fails-because-readfile-is-asynchronous/37501822#37501822) – jfriend00 May 30 '16 at 02:49
  • Those articles all look good, not sure they're good for reading at 4am though. I'll at them to my list. Thanks for the help. – Roooss May 30 '16 at 03:05

1 Answers1

0

I managed to resolve my issue with the help of the following stack question; Calling an asynchronous function within a for loop in JavaScript

Basically I had to refactor a little to get it in the anonymous function but it worked a treat....

youtubeClient.search.list({ part: 'id,snippet', maxResults: 10, q: searchTerm, type: 'video' }, 
    function (err, data) {
        if (err) {
            console.error('Error: ' + err);
        }

        if (data) {
            var returnList = [];

            var total = data.items.length;
            var count = 0;

            for(var i = 0; i < total; i++){
                var returnItem = {};

                (function(foo){
                    returnItem = {
                        duration: '00:00',
                        value: data.items[foo].id.videoId
                    };

                    youtubeClient.videos.list({ part: 'contentDetails', id: returnItem.value }, 
                        function (err, details) {
                            if (err) {
                                console.error('Error: ' + err);
                            }

                            if (details) {
                                returnItem.duration = details.items[0].contentDetails.duration;

                                returnList.push(returnItem);
                            }

                            count++;
                            if (count > total - 1) {
                                // I CAN EXIT FROM HERE NOW
                            }
                    });

                }(i));
            }
        }
    });
Community
  • 1
  • 1
Roooss
  • 626
  • 1
  • 9
  • 24