如何 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 在 findRecordthen 解决之后。我该怎么做?

所以这是 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 因为它依赖于异步任务来完成。我看到的两个选项是:

  1. 重新设计计算的 属性 以使用 PromiseProxyMixin 对象。 (这会使情况过于复杂,在这种情况下我不推荐)
  2. 一起放弃使用 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 的组件,负责将模型与适合显示目的的格式相互转换。