在目前的Ember文档中重复了几次,所以我觉得我必须遗漏一些东西。我们来看simplest example I found。
为什么对levelUp的调用被认为是异步的,以保证在运行循环中包装它? incrementProperty是同步的,据我所知,set也是如此(但我可能会在这里弄错)
player.js
import DS from 'ember-data';
export default DS.Model.extend({
level: DS.attr('number', { defaultValue: 0 }),
levelName: DS.attr('string', { defaultValue: 'Noob' }),
levelUp() {
let newLevel = this.incrementProperty('level');
if (newLevel === 5) {
this.set('levelName', 'Professional');
}
}
});
玩家test.js
import { moduleForModel, test } from 'ember-qunit';
import Ember from 'ember';
moduleForModel('player', 'Unit | Model | player', {
// Specify the other units that are required for this test.
needs: []
});
test('should increment level when told to', function(assert) {
// this.subject aliases the createRecord method on the model
const player = this.subject({ level: 4 });
// wrap asynchronous call in run loop
Ember.run(() => player.levelUp());
assert.equal(player.get('level'), 5, 'level gets incremented');
assert.equal(player.get('levelName'), 'Professional', 'new level is called professional');
});
答案 0 :(得分:2)
首先,你是绝对正确的。在指南的任何地方都没有详细描述。
在测试模式下,禁用自动运行。您可以从the guides进一步了解这一点。
但更改模型中的值会触发一个运行循环。您可以在this twiddle看到它。结果是:
断言失败:您已打开测试模式,禁用了 run-loop的自动运行。您将需要使用异步包装任何代码 跑步中的副作用
(顺便说一句,set
和incrementProperty
都会触发此运行循环作为您的猜测。)
然后这是运行循环源:
DS.attr
返回computed property with set。 set
函数triggers an event。 答案 1 :(得分:1)
@ykaragol在他的正确答案中对他的解释是绝对正确的,我没有任何补充,为什么你需要在运行循环中包装你的代码;因为源代码在那里并且正在调用emberRun.schedule
,这需要一个运行循环。
我想解释的更多是关于你得到的断言错误:“你已经打开了测试模式,它禁用了运行循环的自动运行。你将需要包含任何带有异步副作用的代码。跑”。这并不直接意味着异步操作(在进行ajax调用或触发定时器的意义上)就位。我们大多不知道但是; Ember.js确实使用Ember.run
循环和各种运行队列,例如sync
,actions
,render
,afterRender
等,以便安排效果我们的代码,以优化我们的应用程序的呈现。即使代码this.set('levelName', 'Professional');
确实看起来非常同步; Ember将其包装在运行循环中,以便计算属性计算或其他更新被缓冲在一起,以防止模板的多次渲染(从而降低性能)。
我只希望有更好的解释,包括运行循环,运行队列,或者如何以及为什么在测试中使用运行循环,但是没有:(