Were Ember Computed Properties meant to be used wi

2019-09-16 14:02发布

问题:

I'm an experienced Ember.js developer. In guides, we can find an example of Computed Property with full name (synchronous, easy, relies on first name and last name). In the wild, we can find however lots of usages of Computed Properties in an asynchronous manner (for example setting itself after promises resolve - while the first run and get returns undefined).

The more I see this asynchronous Computed Properties the more I wonder - were Computed Properties meant to be used with an asynchronous code? Isn't it asking for trouble?

A common issue is that other Computed Property (CP2) relies on async CP1. CP2 gets CP1 but it gets undefined (as CP1 will set its value in later time as it is async). CP2 finishes its calculation with the wrong value of CP2 (undefined). CP1 sets itself, but CP2 does not recalculate anymore (even CP1 changed) because CP2 isn't referenced in the template (which would mean it is bound and its value is needed all the time, always recalculates when CP1 changes) - but instead was referenced by some JavaScript call.

The real world example of this could be the calculation of total order (from e-commerce shop) price based on items in the order. Computed property relies on asynchronous relationships to items, which could contain other asynchronous relationships, like tax type.

回答1:

I assume you mean mixing computed properties and promises. If you do then don't. I have stumbled upon this issue multiple times. I find it problematic especially with deep nested associations.

I was working on an eCommerce site as well. Initially, I discovered a lot of calculations didn't get resolved when the site rendered. The reason was because I passed promises into computed property(which is used for calculation). Later on, I realized I should resolve all relationships before passing results into calculation logics instead. I did this step in a service. One example to demonstrate what I mean:

Let's say, order has many items and you want to calculate total price, price is a field in item.

Instead of:

total: Ember.computed("order.items.@.price", function() {
  return this.get("order.items").reduce((sum, obj) => {
    return sum + obj.get("price");
  });
});

I do this:

total: Ember.computed("items.@.price", function() {
   return this.get("items").reduce((sum, obj) => {
     return sum + obj.get("price");
   });
});

where items is passed in as a promise result somewhere above.

I found this post explains why-you-should-not quite well.

I tempted to ask similar question a while back. Keen to hear more ideas about this.