Question

I have the following code that gets the JSON from an array of YouTube video ids. It works great when all the videos exists and the query is successful. It sends several getJSON request, and when all of them are done... the $.when.done() fires and I can process the resulting data.

var
  results  = {},
  promises = [];

$(document).ready(function() {

  var
    vids = [
    'ozj2-bnTL3s',
    'EAZ4Tlt8MQ4',
    'Xn9o7cxqVoA'
    // ,'this-videoid-doesnot-exists'
  ],
  url = 'http://gdata.youtube.com/feeds/api/videos/{{vid}}?v=2&alt=json';

  $.each(vids, function(idx, vid){
    var
      u = url.replace('{{vid}}', vids[idx]),
      p = null;

    p = $.getJSON( u ).done(function(data) {
      results[vid] = data.entry;
    });

    promises.push(p);
  });

  $.when.apply($, promises).done(function(){
    console.log(results);
  });

});

But... In the final app I don't control if all the videos still exists in YouTube, I've realized that sometimes one (or several) of the videos in the list may have been deleted... or the id that I get from the DB is incorrect.

Is there any way that I could safely add to the results variable only the videos that where successful whiteout trigger the $.when.fail()? and waiting that all the queries had finished...

I mean, my final goal is to get the data from the videos that exist (those that its data was successfully retrieved), and, somehow to ignore those that don't exist or where unavailable... and I don't figure right now how to do it.

Any idea / approach will be appretiated. TIA!
You can find the code in this JSFiddle

Was it helpful?

Solution

Unfortunately, jQuery doesn't come with this functionality.

Gladly, you can implement it yourself pretty easily.

var url = 'http://gdata.youtube.com/feeds/api/videos/{{vid}}?v=2&alt=json';
function getVideo(vid){
    var u = url.replace('{{vid}}', vid);
    return $.getJSON( u ).then(function(res){
         return {video:vid,result:res.entry};
    });
}
var promises = ['ozj2-bnTL3s','EAZ4Tlt8MQ4',"doesn'texist"].map(getVideo);

some(promises).then(function(results){
    for(var i = 0; i < results.length; i++) {
        console.log(results[i]); // log
    }
});



// get a hook on when all of the promises resolve, some fulfill
// this is reusable, you can use this whenever you need to hook on some promises
// fulfilling but all resolving.
function some(promises){
    var d = $.Deferred(), results = [];
    var remaining = promises.length;
    for(var i = 0; i < promises.length; i++){
        promises[i].then(function(res){
            results.push(res); // on success, add to results
        }).always(function(res){
            remaining--; // always mark as finished
            if(!remaining) d.resolve(results);
        })
    }
    return d.promise(); // return a promise on the remaining values
}

Here's a working JSFiddle of the result.

OTHER TIPS

In a purely javascript Promise implementation (or a specialised library like Q or another), you could do this:

function getVideo(id) {
  return new Promise(function(resolve, reject) {
    var request = new XMLHttpRequest();
    request.open('GET', 'url = 'http://gdata.youtube.com/feeds/api/videos/' + id + '?v=2&alt=json');
    request.onload = function() {
      if (request.status == 200) {
        resolve(request.response); //we get the data here. So, resolve the Promise
      } else {
        reject(Error(request.statusText)); //if status is not 200 OK, reject.
      }
    };

    request.onerror = function() {
      reject(Error("Error fetching data.")); //error occurred, reject the Promise
    };

    request.send(); //send the request
  });
}

function fetchVideos() {
  var vids = [
    'ozj2-bnTL3s',
    'EAZ4Tlt8MQ4',
    'Xn9o7cxqVoA'
    // ,'this-videoid-doesnot-exists'
  ]
  var promises = [];
  for (var i in vids) {
    promises.push(getVideo(vids[i]));
  }
  Promise.all(promises).then(function(dataArr) {
    dataArr.forEach(function(data) {
      console.log(data.entry);
    });
  }).catch(function(err){
      console.log(err);
  });
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top