我有以下三种模式:
ConversationApp.Post = DS.Model.extend(
body: DS.attr()
replies: DS.hasMany('reply', async: true)
author: DS.belongsTo('user', async: true)
likedBy: DS.hasMany('user', async: true)
)
ConversationApp.Reply = DS.Model.extend(
body: DS.attr()
post: DS.belongsTo('post')
author: DS.belongsTo('user', async: true)
likedBy: DS.hasMany('user', async: true)
)
ConversationApp.User = DS.Model.extend(
firstName: DS.attr()
lastName: DS.attr()
)
我的索引路线就是这个电话:
ConversationApp.IndexRoute = Em.Route.extend(
model: (args) ->
@store.find('post', page: 1) # => /api/v1/posts?page=1
)
在进行该呼叫之后,Ember开始获取第一页所需的所有用户 - 在第一页上共有17个(!)不同的用户请求(10个帖子)。以下是Ember向服务器发出的3个请求示例:
我希望Ember只发出一个请求,请求第一页所需的所有用户:
把手文件如下所示:
{{#each}}
{{author.firstName}}
{{#each likedBy}}
[... removed for brevity ...]
{{/each}}
{{#each replies}}
{{author.firstName}}
{{#each likedBy}}
[... removed for brevity ...]
{{/each}}
{{/each}}
{{/each}}
我该如何实现?
答案 0 :(得分:9)
我知道这是一个旧线程,但这是使用DS.RESTAdapter
的解决方案。
实现这一目标非常容易。您唯一要做的就是将coalesceFindRequests
设置为true
,如下所示:
App.ApplicationAdapter = DS.RESTAdapter.extend({
coalesceFindRequests: true
});
或者如果您使用Ember CLI
// app/adapters/application.js
import DS from 'ember-data';
export default DS.RESTAdapter.extend({
coalesceFindRequests: true
});
中详细了解相关信息
祝你好运! :)
答案 1 :(得分:3)
所以我对此嗤之以鼻。不幸的是,我不相信Ember-Data提供了开箱即用的这种功能。但它似乎并不难实现。我的方法是使用去抖动器。基本上,每次发出用户请求时,请求都会被放入池中。池填满,直到足够长的时间段(我的代码中为50ms)没有其他请求。在此之后,请求全部一起发送,池被清空。然后,当巨大的请求返回时,它被分解为较小的请求,可以用来完成最初在池中的请求。
请记住,我还没有对此进行测试,但这应该显示出一般的想法。
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'));
};
})()
});
编辑:我使用单元测试设置了一个快速JSBin,它似乎运行正常。这是一个相当脆弱的测试,但它表明这个想法运作良好。
答案 2 :(得分:0)
我对Ember Data不太熟悉,但我认为这不是Ember的错。您可以尝试更改JSON API以侧载相关数据。
Ember Data使用JSON API作为json标准。它描述了关系的格式,以及如何在一个请求中发送数据及其关系。
如果一切正常(将来),请求/api/v1/posts
中,如果你想侧面加载所有回复,你可以像这样构建json:
{
"posts": [{
"id": "1",
"body": "post body 1",
"links": {
"replies": ["1", "2"]
}
}, {
"id": "2",
"body": "post body 2",
"links": {
"replies": ["3"]
}
}],
"linked": {
"replies": [{
"id": "1",
"body": "reply body 1"
}, {
"id": "2",
"body": "reply body 2"
}, {
"id": "3",
"body": "reply body 3"
}]
}
}
不幸的是它现在还没有用。我检查了最新的Ember数据源,找不到任何带有“链接”支持的代码。
如果您正在使用Rails和ActiveModelSerializer,另一种工作方式是使用嵌入数据,请参阅此Ember Data test了解嵌套数据格式。
JSON API和Ember Data都是未完成的项目。这意味着未来一切都可能发生变化,即使在今天,Ember Data也不完全支持JSON API。因此,如果您想在现实世界项目中使用Ember Data。您必须非常熟悉它的架构,并能够自定义适配器和放大器。序列化器供您自己使用。