1
\$\begingroup\$

Want to brush up my rusty web dev skills. I want to call the twitch API for several channels and eventually call a callback function when all results are in without using a sync call.

I didn't work with JavaScript for a long time, so I'm not sure if my solution is a good way, especially how I figure out if the callback function should be called.

var Twitch = function() {
    var baseUrl = 'https://api.twitch.tv/kraken/streams/';
    var channels = ["freecodecamp", "storbeck", "terakilobyte", "habathcx", "RobotCaleb", "thomasballinger", "noobs2ninjas", "beohoff"];

    this.update = function(callback) {
        var result = {};
        for (var i = 0; i < channels.length; i++) {
            var qUrl = baseUrl + channels[i];
            var name = channels[i];
            $.getJSON(qUrl, success(name, result, callback));
        }
    }

    function success(name, result, callback) {
        return function(data) {
            result[name] = data;
            if (results.length == channels.length) {
                callback(result);
            }
        }
    }
};
\$\endgroup\$
2
  • 1
    \$\begingroup\$ I can't elaborate a really good answer, you can take a look at $.when to think in an alternative way of do the same job \$\endgroup\$ – Daniele Mar 25 '16 at 13:38
  • \$\begingroup\$ Didn't saw this, looks nice. Thanks for the hint! \$\endgroup\$ – Mirco Mar 25 '16 at 13:40
1
\$\begingroup\$

I suppose this code is used like:

var twitch = new Twitch();
twitch.update(function(){
  // called each time a site responds
});

A few things:

First, I see little benefit of this functionality being written using a constructor. It appears to be a singleton by functionality as it makes no sense spawning multiple instances. Consider a singleton instead:

var Twitch = (function(){

  // stuff

  return {
    update: function(){...}
  };

}());

Next is your AJAX. As pointed in the comments, use $.when to listen to multiple jqXHR objects and call the callback once everyone is resolved. The native counterpart to $.when is Promise.all.

Next is to make update return a promise instead of handing it a callback. This way, your caller is allowed to listen not only for the success but also the failures.

Next is to take advantage of array methods like map instead of loops.

Your code could be simplified into:

var Twitch = (function(){

  var baseUrl = 'https://api.twitch.tv/kraken/streams/';
  var channels = ["freecodecamp", "storbeck", "terakilobyte", "habathcx", "RobotCaleb", "thomasballinger", "noobs2ninjas", "beohoff"];

  return {
    update: function(){
      var promises = channels.map(function(channel){
        return $.getJSON(baseUrl + channel).then(function(data){
          var result = {};
          result[channel] = data;
          return result;
        });
      });

      return $.when.apply(null, promises).then(function(){
        var args = Array.prototype.slice.call(arguments);
        return args.reduce(function(results, result){
          return $.extend(results, result);
        }, {});
      });
    }
  };

}());

// Usage
Twitch.update().then(function(results){
  // Succeeded
}, function(){
  // Failed
});

Now if you have ES6 available (via transpiler, or a modern browser), this can be simplified further by using the new syntax and making it more compact.

var Twitch = (function(){

  var baseUrl = 'https://api.twitch.tv/kraken/streams/';
  var channels = ["freecodecamp", "storbeck", "terakilobyte", "habathcx", "RobotCaleb", "thomasballinger", "noobs2ninjas", "beohoff"];

  return {
    update(){
      var promises = channels.map(channel => {
        return $.getJSON(`${baseUrl}${channel}`)
                .then(data => ({[channel]: data}));
      });

      return Promise.all(promises)
                    .then((...args) => args.reduce((results, result) => Object.assign(results, result), {}));
    }
  };

}());

// Usage
Twitch.update().then(function(results){
  // Succeeded
}, function(){
  // Failed
});
\$\endgroup\$
1
  • \$\begingroup\$ Thanks for giving me good hints where to look next. Can't remember promises where s thing when I worked with JS last time \$\endgroup\$ – Mirco Mar 26 '16 at 7:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.