Jim  Moriarty Jim Moriarty - 2 months ago 6
Ajax Question

How to create a javascript object with multiple AJAX properties?

I have a javascript project with legacy code. There is creating an object with properties via synchronous ajax. Something like this:

function App() {
this.users = $.parseJSON(
$.ajax({
url: '/users'
datatype: "json"
async: false
}).responseText);

this.items = $.parseJSON(
$.ajax({
url: '/items'
datatype: "json"
async: false
}).responseText);

this.pets = $.parseJSON(
$.ajax({
url: '/pets'
datatype: "json"
async: false
}).responseText);
}


Of course, this properties are avalible in the object after initialization. But now, I need to rewrite it with async Ajax requests.
So, here is my question: is there a best practice to create an object with many Ajax properties?

P.S.: I have an idea — to use promises chain and create object after all requests. But I want to know: is there any solutions?

Answer

Your idea is very close. It's not so much a chain, the ajax calls can run in parallel, but you need to know when they've all finished. jQuery has just the thing for you: $.when:

function App() {
    var t = this;
    t.readyPromise = $.when(
        $.ajax({
          url: '/users',
          dataType: "json",
          success: function(data) {
              t.users = data;
          }
        }),
        $.ajax({
          url: '/items',
          dataType: "json",
          success: function(data) {
              t.items = data;
          }
        }),
        $.ajax({
          url: '/pets',
          dataType: "json",
          success: function(data) {
              t.pets = data;
          }
        })
    );
}

Since App looks like a constructor, I'll note that the instance you get from new App() won't be ready to use until its readyPromise resolves. You might reorganize the code so that you don't have a partially-constructed object (partially-constructed objects tend to be a bad idea). We can also make use of the way $.when collects the results of promises for us:

function App(users, items, pets) {
    this.users = users;
    this.items = items;
    this.pets = pets;
}
App.get = function() {
    return $.when(
        $.ajax({
          url: '/users',
          dataType: "json"
        }),
        $.ajax({
          url: '/items',
          dataType: "json"
        }),
        $.ajax({
          url: '/pets',
          dataType: "json"
        })
    ).then(function(users, items, pets) {
        return new App(users, items, pets);
    });
};

Usage:

App.get().then(function(app) {
    // use `app` here
});

Live Example:

function fakeAjax(opts) {
  var d = $.Deferred();
  setTimeout(function() {
    d.resolve(["some " + opts.url.substring(1)]);
  }, Math.floor(Math.random() * 500));
  return d.promise();
}
function App(users, items, pets) {
  this.users = users;
  this.items = items;
  this.pets = pets;
}
console.log("Getting...");
App.get = function() {
  return $.when(
    fakeAjax({
      url: '/users',
      dataType: "json"
    }),
    fakeAjax({
      url: '/items',
      dataType: "json"
    }),
    fakeAjax({
      url: '/pets',
      dataType: "json"
    })
  ).then(function(users, items, pets) {
    return new App(users, items, pets);
  });
};

// Usage:
App.get().then(function(app) {
  console.log(app);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


Side note: It's dataType, not datatype; I've fixed it in the above. There were also essential missing commas.

Comments