So I took a stab at this. Unfortunately, I don't believe Ember-Data provides this kind of functionality out of the box. But it doesn't seem to difficult to implement. My approach was to use a debouncer. Basically, every time a request for users is made, the request is put into a pool. The pool fills up until a long enough period has gone by (50ms in my code) without another request. After that time, the requests are all sent together and the pool is emptied. Then, when the giant request comes back, it's broken up into smaller ones that can be used to fulfill the requests that were originally in the pool.
Keep in mind, I haven't tested this yet, but this should show the general idea.
App.UserAdapter = DS.RESTAdapter.extend({
_findMany: null,
find: function(store, type, id) {
return this.findMany(store, type, [id]);
},
findMany: function(store, type, ids) {
this._findMany = this._super;
// Create a promise, but keep the resolve function so we can call it later
var resolve;
var promise = new Ember.RSVP.Promise(function(r) {
resolve = r;
});
// Let our debouncer know about this request
this.concatenateRequest(store, ids, resolve);
// Return a promise as usual
return promise;
},
/**
* The number of milliseconds after a request to wait before sending it.
* Tweak this as necessary for performance.
*/
debounceTimeout: 50,
concatenateRequest: (function() {
// All of the IDs currently requested in the pool
var allIds = new Em.Set();
// The pool of promises that is currently awaiting fulfillment
var allPromises = [];
// The ID of the last `setTimeout` call
var timeout = null;
// Takes the specified users out of the payload
// We do this to break the giant payload into the small ones that were requested
var extractUsers = function(payload, ids) {
// Filter out the users that weren't requested
// Note: assuming payload = { users: [], linked: {}, meta: {} }
var users = payload.users.filter(function(user) {
return (ids.indexOf(user.id.toString()) >= 0);
});
// Return payload in form that store is expecting
return { users: users };
};
return function(store, ids, resolve) {
// clear the timeout (if it's already cleared, no effect)
clearTimeout(timeout);
// Add the current promise to the list of promises to resolve
allIds.addObjects(ids);
allPromises.push({ ids: ids, resolve: resolve });
// Set our timeout function up in case another request doesn't come in time
timeout = setTimeout(function() {
// Get the IDs and promises store so far so we can resolve them
var ids = allIds.toArray();
var promises = allPromises;
// Clear these so the next request doesn't resolve the same promises twice
allIds = new Em.Set();
allPromises = [];
// Send off for the users we know need
this._findMany(store, ConversationApp.User, ids).then(function(payload) {
// Resolve each promise individually
promises.forEach(function(promise) {
// extract the correct users from the payload
var users = extractUsers(payload, promise.ids);
// resolve the promise with the users it requested
promise.resolve(users);
});
});
}.bind(this), this.get('debounceTimeout'));
};
})()
});
EDIT: I set up a quick JSBin with a unit test and it seems to function OK. It's a pretty fragile test, but it shows that the idea works well enough.