承诺结果 Ember 数据计算 属性

Promise result in Ember Data computed property

我正在尝试调用外部 API 并将结果用作我的 Ember 数据模型中的计算结果 属性。结果被很好地获取,但是在 Promise 解析之前计算的 属性 returns 导致未定义。这是观察者的用例吗?

export default DS.Model.extend({
  lat: DS.attr(),
  lng: DS.attr(),
  address: Ember.computed('lat', 'lng', function() {
    var url = `http://foo.com/json?param=${this.get('lat')},${this.get('lng')}`;
    var addr;

    var request = new Ember.RSVP.Promise(function(resolve, reject) {             
        Ember.$.ajax(url, {                                                        
          success: function(response) {                                            
            resolve(response);                                                     
          },                                                                       
          error: function(reason) {                                                
            reject(reason);                                                        
          }                                                                        
        });                                                                        
     });                                                                          

     request.then(function(response) {                      
       addr = response.results[0].formatted_address;                              
     }, function(error) {                                                         
       console.log(error);
     })  

     return addr;
  })
});

创建组件(地址-display.js):

import Ember from 'ember';

export default Ember.Component.extend({
  init() {
    var url = `http://foo.com/json?param=${this.get('lat')},${this.get('lng')}`;
    Ember.$.ajax(url, {
      success: function(response) {
        this.set('value', response.results[0].formatted_address);
      },
      error: function(reason) {
        console.log(reason);
      }
    });
  }
});

模板(components/address-display.hbs):

{{value}}

然后在您的模板中使用该组件:

{{address-display lat=model.lat lng=model.lng}}

下面的工作是在 属性 内部解析并设置结果。

这里解释: http://discuss.emberjs.com/t/promises-and-computed-properties/3333/10

export default DS.Model.extend({
  lat: DS.attr(),
  lng: DS.attr(),
  address: Ember.computed('lat', 'lng', function() {
    var url = `http://foo.com/json?param=${this.get('lat')},${this.get('lng')}`;
    var self = this;

    var request = new Ember.RSVP.Promise(function(resolve, reject) {             
        Ember.$.ajax(url, {                                                        
          success: function(response) {                                            
            resolve(response);                                                     
          },                                                                       
          error: function(reason) {                                                
            reject(reason);                                                        
          }                                                                        
        });                                                                        
     }).then(function(response) {
         self.set('address', response.results[0].formatted_address);
     })
  })
});

我已经在大型 Ember 应用程序中使用 self.set('computed_property', value); 技术大约三个月了,我可以告诉你它有一个非常大的问题:计算的 属性 只会工作 一次.

当您 set 计算 属性 值时,生成结果的函数将丢失,因此当您的相关模型属性更改时,计算 属性 将不会刷新。

在 Ember 中的计算属性中使用 promises 很麻烦,我发现的最佳技术是:

prop: Ember.computed('related', {
    // `get` receives `key` as a parameter but I never use it.
    get() {
        var self = this;
        // We don't want to return old values.
        this.set('prop', undefined);
            promise.then(function (value) {
                // This will raise the `set` method.
                self.set('prop', value);
            });
        // We're returning `prop_data`, not just `prop`.
        return this.get('prop_data');
    },
    set(key, value) {
        this.set('prop_data', value);
        return value;
    }
}),

优点:

  • 它适用于模板,因此您可以在模板中执行 {{object.prop}},它会正确解析。
  • 它会在相关属性更改时更新。

缺点:

  • 当你在 Javascript object.get('prop'); 中执行并且 promise 正在解决时,它会 return 你立即 undefined,但是如果你正在观察计算 属性,当 promise 解析并设置最终值时,观察者将再次触发。

也许您想知道为什么我没有 return在 get 中做出承诺;如果你这样做并在模板中使用它,它将呈现一个对象字符串表示([object Object] 或类似的东西)。

我想在模板中运行良好的适当计算 属性 实现中工作,return Javascript 中的承诺并自动更新,可能使用类似 DS.PromiseObject or Ember.PromiseProxyMixin, 可惜我没时间。

如果大骗局对您的用例来说不是问题,请使用 "get/set" 技术,如果不是,请尝试实施更好的方法,但认真 不要只使用 self.set('prop', value);,从长远来看会给你带来很多问题,不值得。

PS.:然而,这个问题真正的、最终的解决方案是:如果可以避免的话,永远不要在计算属性中使用 promises。

PS.:顺便说一下,这个技术不是我的,而是我的前同事@reset-reboot。

使用DS.PromiseObject。我一直使用以下技术:

import DS from 'ember-data';

export default DS.Model.extend({

  ...

  address: Ember.computed('lat', 'lng', function() {
    var request = new Ember.RSVP.Promise(function(resolve, reject) {             
      ...
    });                                                                          

    return DS.PromiseObject.create({ promise: request });
  }),

});

在模板中使用已解析的值作为 {{address.content}},它将在代理的 Promise 解析时自动更新。

如果您想在这里做更多事情,我建议您查看社区中的其他人在做什么:https://emberobserver.com/?query=promise

构建一个简单的组件并不难.

我在我工作的应用程序中有一个 Ember.Service,它几乎完全由 return 包裹在 DS.PromiseObjects 中的计算属性组成。它运行起来非常顺畅。