我在模型中有一个“虚拟属性”,我希望设置器在返回值之前先等待promise:
idShop:Ember.computed('shop',function(){
get(key){
return this.get('shop').id;
},
set(k,v){
this.get('store').findRecord('shop',key)
.then(shop =>{
this.set('shop', shop)
})
}
})
在集合中,我需要在findRecord
之后得到k(key)或shop.id,并且then
被求解。我该怎么办?
答案 0 :(得分:2)
因此,这是Ember Concurrency.
的绝佳用例 Ember并发(EC)在其function * () {}
方法中使用生成器函数task()
使管理此类事情变得更加容易。任务还提供了一些实用程序属性,以显示其当前是running
还是idle
(又称为加载数据,或已完成加载数据)。
这是我要设置的方式(余烬2.17及更高版本的代码)
import {task} from 'ember-concurrency';
import {computed} from '@ember/object';
# skip ahead to later in the code...
shop: null,
loadShop: task(function*(key) {
let shop = yield this.get('store').findRecord('shop', key)
this.set('shop', shop)
}),
shopId: computed('shop', function() {
if (this.get('shop') {
return this.get('shop.id);
} else {
return null;
}
})
根据您的确切用例,当您知道ID是什么(可能在init钩子或在单独的方法中)时,您将调用this.get('loadShop').perform(id)
(注意:将属性作为计算属性的一部分进行更改是一种不好的做法。计算后的属性实际上应该是无状态的。)
答案 1 :(得分:1)
从设计的角度来看,这是一个很大的危险信号。在这种情况下,我将不使用设置器,因为它取决于异步任务的完成。我看到的两个选项是:
PromiseProxyMixin
对象。 (这会使情况变得过于复杂,在这种情况下,我不建议这样做)如果您将模型发送到该属性而不是密钥,我将更容易推断。如果这是一个问题,因为您坚持使用双向绑定输入助手,那么请查看该选择器的DDAU版本,以便它调用操作而不是设置属性。或将其包装在一个组件中,该组件知道如何将键转换为模型,然后在解决后在关系上设置模型。
我认为@ donald-wasserman通过他的ember-concurrency示例来建议稍后。但是,您的情况并非必需。它将提供一些好处(取消),但是我不会陷入解决方案的余烬并发部分,而不会陷入设计如何以及在何处执行异步查找的设计。
异步依赖性更容易推断何时将它们作为操作而不是作为计算属性的副作用执行。 CP并非真正用于异步事物。我知道在某些情况下可以使用代理(即ember-data)来摆脱它,但是它确实引入了一定程度的认知负担,可以很快失去控制。 默认为异步需求的操作。
对于普通选择,您将必须具有可将字符串键转换为模型查找的转换层(因此是组件)。一些选择的插件会为您做到这一点(例如ember-power-select)。查找翻译是组件而不是模型的责任,这可能就是您遇到麻烦的原因。
关于向模型添加方法以执行异步查找:您可以执行此操作,但是我认为这可能是一个糟糕的设计选择,因为它混合/模糊了职责范围。 (即Single Responsibility Principle of S.O.L.I.D.)
换句话说,选择的需要是表示方面的问题。需要将字符串(用于表示逻辑)转换为模型(用于业务逻辑)的事实实际上不是模型的责任。该模型应负责仅存储关系。正是呈现选择的组件负责将模型与适用于显示目的的格式相互转换。