如何 return 基于 promise 的数据
How to return data based on promise
我在模型中有一个 "virtual attribute",我希望 setter 在 return 值之前等待承诺:
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)
})
}
})
在集合中,我需要 return k(key) 或 shop.id 在 findRecord
和 then
解决之后。我该怎么做?
所以这是 Ember Concurrency.
的一个很好的用例
Ember 并发 (EC) 在其 task()
方法中使用生成器函数 function * () {}
来简化此类管理。任务还提供了一些实用属性来显示它当前是 running
还是 idle
(又名加载数据,或完成加载数据)。
以下是我的设置方式(ember 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 是什么时(可能在 in init 挂钩中或在单独的方法中),您会调用 this.get('loadShop').perform(id)
(注意:将属性作为计算的一部分进行变异是一种不好的做法 属性。计算属性确实应该是无状态的。)
从设计的角度来看,这是一个大危险信号。在这种情况下我不会使用 setter 因为它依赖于异步任务来完成。我看到的两个选项是:
- 重新设计计算的 属性 以使用
PromiseProxyMixin
对象。 (这会使情况过于复杂,在这种情况下我不推荐)
- 一起放弃使用 setter。将 属性 设置为只读并添加一个你调用的方法来设置它,它可以 return 一个承诺。
如果您向 属性 发送模型而不是密钥,我会更容易推理。如果这是一个问题,因为您坚持使用双向绑定输入助手,那么请查看该 select 的 DDAU 版本,或者这样它会调用一个操作而不是设置一个 属性。或者将其包装在一个组件中,该组件知道如何将键转换为模型,然后在解析后在关系上设置模型。
我认为@donald-wasserman 用他的 ember-concurrency 示例建议后者。但是,您的情况不需要。它会提供一些好处(取消),但我不会陷入解决方案的 ember- 并发部分,而是陷入有关如何以及在何处执行异步查找的设计中。
异步依赖项更容易推断它们何时作为操作执行,而不是作为计算属性的副作用。 CP 并不是真正用于异步事物。我知道在某些情况下可以使用代理(即 ember-data)来摆脱它,但它确实引入了一定程度的认知负荷,很快就会失控。 默认为满足异步需求的操作。
对于香草 select 你必须有一个翻译层(因此组件)可以将字符串键转换为模型查找。一些 select 插件会为你做这件事(例如 ember-power-select)查找翻译是组件而不是模型的责任,这可能是你 运行 遇到困难的原因。
关于向模型添加方法以执行异步查找:您可以这样做,但我认为这可能是一个糟糕的设计选择,因为它 mixes/blurs 职责范围。 (即 Single Responsibility Principle of S.O.L.I.D.)
换句话说 select 的需求是一个表达关注点。需要将字符串(用于表示逻辑)转换为模型(用于业务逻辑)的事实实际上不是模型的责任。该模型应该负责只存储关系。它是呈现 select 的组件,负责将模型与适合显示目的的格式相互转换。
我在模型中有一个 "virtual attribute",我希望 setter 在 return 值之前等待承诺:
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)
})
}
})
在集合中,我需要 return k(key) 或 shop.id 在 findRecord
和 then
解决之后。我该怎么做?
所以这是 Ember Concurrency.
的一个很好的用例Ember 并发 (EC) 在其 task()
方法中使用生成器函数 function * () {}
来简化此类管理。任务还提供了一些实用属性来显示它当前是 running
还是 idle
(又名加载数据,或完成加载数据)。
以下是我的设置方式(ember 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 是什么时(可能在 in init 挂钩中或在单独的方法中),您会调用 this.get('loadShop').perform(id)
(注意:将属性作为计算的一部分进行变异是一种不好的做法 属性。计算属性确实应该是无状态的。)
从设计的角度来看,这是一个大危险信号。在这种情况下我不会使用 setter 因为它依赖于异步任务来完成。我看到的两个选项是:
- 重新设计计算的 属性 以使用
PromiseProxyMixin
对象。 (这会使情况过于复杂,在这种情况下我不推荐) - 一起放弃使用 setter。将 属性 设置为只读并添加一个你调用的方法来设置它,它可以 return 一个承诺。
如果您向 属性 发送模型而不是密钥,我会更容易推理。如果这是一个问题,因为您坚持使用双向绑定输入助手,那么请查看该 select 的 DDAU 版本,或者这样它会调用一个操作而不是设置一个 属性。或者将其包装在一个组件中,该组件知道如何将键转换为模型,然后在解析后在关系上设置模型。
我认为@donald-wasserman 用他的 ember-concurrency 示例建议后者。但是,您的情况不需要。它会提供一些好处(取消),但我不会陷入解决方案的 ember- 并发部分,而是陷入有关如何以及在何处执行异步查找的设计中。
异步依赖项更容易推断它们何时作为操作执行,而不是作为计算属性的副作用。 CP 并不是真正用于异步事物。我知道在某些情况下可以使用代理(即 ember-data)来摆脱它,但它确实引入了一定程度的认知负荷,很快就会失控。 默认为满足异步需求的操作。
对于香草 select 你必须有一个翻译层(因此组件)可以将字符串键转换为模型查找。一些 select 插件会为你做这件事(例如 ember-power-select)查找翻译是组件而不是模型的责任,这可能是你 运行 遇到困难的原因。
关于向模型添加方法以执行异步查找:您可以这样做,但我认为这可能是一个糟糕的设计选择,因为它 mixes/blurs 职责范围。 (即 Single Responsibility Principle of S.O.L.I.D.)
换句话说 select 的需求是一个表达关注点。需要将字符串(用于表示逻辑)转换为模型(用于业务逻辑)的事实实际上不是模型的责任。该模型应该负责只存储关系。它是呈现 select 的组件,负责将模型与适合显示目的的格式相互转换。