Make Simultaneous HTTP Requests That Resolve Into a Single Return This week, in an ongoing job search, I was tasked with the following pre-screening question:


  Make two simultaneous http requests. Use the language and library of your choice. Make sure the results are combined and resolve into a single return.


For this I chose JavaScript and jQuery, culminating in the following Gist and jsFiddle.

fiddle.js:

var gistID = '275cd1b76574497327761b33fb08ad4d';

function Source(url){
 this.url = url;
};

var source = new Source("/gh/gist/response.html/" + gistID + "/");
var sources = [source,source];

function asyncGroup() {

 var promises = [];

 sources.forEach(function(source,index,sources){

  var deferred = jQuery.Deferred();

  promises.push(deferred.promise());

  $.ajax({url: source.url, processData: false}).always(function(data){
   sources[index].element = '&lt;img src="data:image/png;base64,' + data + '"/&gt;';
   deferred.resolve();
  });
 });
 return promises;
}

$.when.apply(null, asyncGroup() ).done(function( status ) {

 sources.forEach(function(source){$("#myDiv").append($(source.element));});
 $("#myDiv").show();
});


One thing I would like to change is to accredit Fiddle Author Casiano Rodriguez-Leon for their base64 testing image, provided it remains in the implementation. Perhaps this is best done in fiddle.manifest, I am not sure.

Beyond that, I know that much can be improved, and I'm all ears.
Compatibility aside, you can skip jQuery. Everything you need is present in vanilla JS. jQuery AJAX can be replaced by fetch and deferreds can be replaced by native Promise. As an added bonus, use template literals to easily construct strings.

// Work on the very basic data, the IDs
const ids = [
  '275cd1b76574497327761b33fb08ad4d',
  '275cd1b76574497327761b33fb08ad4d'
];

// Map IDs into urls
const urls = ids.map(id =&gt; `/gh/gist/response.html/${id}/`);

// Construct a function that transforms the Response object into an img
const responseToImage = res =&gt; `&lt;img src="data:image/png;base64,${res.text()}"/&gt;`;

// For each, send request, convert response to img, and store promise in array
const promises = urls.map(url =&gt; fetch(url).then(responseToImage));

// Wait until all promises resolve, then append image
Promise.all(promises).then(images =&gt; {
  const container = $('#myDiv').show();
  images.forEach(image =&gt; container.append(image));
});




As for your code, a few things

var gistID = '275cd1b76574497327761b33fb08ad4d';

function Source(url){
 this.url = url;
};

var source = new Source("/gh/gist/response.html/" + gistID + "/");
var sources = [source,source];


This code doesn't look scalable. If say I wanted to add more images, different images, there is no way for this code to do that without having to modify several lines of code. In this case, gistId has to be abandoned, you'd have to write new Source(...) for each item, and update the sources array.

Also, insider tip: It's a bad sign if a really simple code update results in modification of several lines. Also, writing code this way results to bad habits which can hurt in the long run.

function asyncGroup() {

 var promises = [];

 sources.forEach(function(source,index,sources){

  var deferred = jQuery.Deferred();

  promises.push(deferred.promise());

  $.ajax({url: source.url, processData: false}).always(function(data){
   sources[index].element = '&lt;img src="data:image/png;base64,' + data + '"/&gt;';
   deferred.resolve();
  });
 });
 return promises;
}


The $.ajax function already returns a Deferred-like, jqXHR object. You don't need to "wrap" it in a Deferred, this is already redundant. You can simply push its return value to the array. Additionally, when doing 1:1 conversion from one array to another, array.map is the function you want. With these, you can remove all that boilerplate code to transform source.url to an array of deferreds.

$.when.apply(null, asyncGroup() ).done(function( status ) {
 sources.forEach(function(source){$("#myDiv").append($(source.element));});
 $("#myDiv").show();
});


You can cache the result of $('#myDiv') in a variable so that you don't have to call it repeatedly. Additionally, jquery.append accepts HTML strings as argument. No need to convert it first.