我需要将一组原始数据转换为Ember模型。我可以通过在数组上实现forEach循环并为数组中的每个对象创建模型来实现。
问题在于我可能有数百或数千个模型需要循环,这将需要10秒以上。只要我有办法向用户显示进度条以便他们知道应用程序没有冻结以及他们需要等待多长时间,我就可以花很长时间。
App.ApplesController = Ember.Controller.extend({
// array with possibly thousands of objects in it
applesJson: Ember.A(),
// we'll be dumping the newly created models in here
applesModels: Ember.A(),
buildAppleModels: function () {
var applesJson = this.get('applesJson'),
applesModels = Ember.A();
applesJson.forEach(function (appleJson) {
var apple = self.store.createRecord('apple', appleJson);
applesModels.push(apple);
console.log('pushed an apple');
});
},
ghettoProgressBar: function () {
var complete = this.get('applesModels.length'),
total = this.get('applesJson.length');
return "Progress: " + complete + " out of " + total;
}.property('applesModels.@each')
});
你可能会说这不是我的真实应用,所以不要担心进度条的实现细节或创建模型等。
问题是Ember尝试通过推迟所有DOM更改,直到forLoop结束(进程开始后10到20秒),这意味着如果我将ghettoProgressBar插入到模板,它不会像我希望的那样打勾,而是保持在0,然后在完成所有过程后切换到完成。
请注意控制台日志。这可以按预期工作,随着模型的创建逐渐增加。那是因为它在当时正好发射,而不是被Ember批量用于以后。
有什么想法吗?我一直在考虑如何做这个很长一段时间,并希望得到任何帮助。我希望有一些方法可以迫使Ember尽早清空队列,但是没有找到任何环绕API /指南的东西。
答案 0 :(得分:1)
正如您已经注意到的那样,您需要打破循环并让Ember有机会更新DOM。
我们在用户界面库中一次又一次地看到的模式相同。用户代码在一个上下文中运行,UI在另一个上下偶尔,这两者必须相遇并同步。更常见的情况是,进展变慢。用户不那么频繁,感觉更加缓慢。
这里的方法是"所有周期都可以工作,对UI和#34;没有任何影响。相反的极端将是这样的:
buildAppleModels: function () {
var applesJson = this.get('applesJson'),
applesModels = this.get('applesModels'),
index = 0;
return buildNext();
function buildNext() {
var appleJson = applesJson[index];
if (!appleJson) {
return;
}
var apple = Ember.Object.create(appleJson);
applesModels.addObject(apple);
console.log('pushed an apple');
index++;
Ember.run.next(buildNext);
}
}
这会立即更新UI,但会将流程放慢十倍或更多。
正确的方法是在中间,你做批量工作,然后睡一两个循环让UI赶上。
那就是说,我不排除Ember有某种方式以同步方式震动DOM更新(你可以尝试挖掘他们的Ember.run docs),但即使这样做,我怀疑那会是一个非常好的主意。