cibernox / cibernox/ember-cpm

computedPromise has issues with proper state management

Open
#136 1 comment 1 reaction 0 assignees View on GitHub
Dominant language
JavaScript
Stars
276
Forks
31
PR merge metrics
No merged PRs in 30d

Description

### The Problem

Suppose you are writing code for some DS.Model using `computedPromise`

``` coffeescript
IssueThread = DS.Model.extend
comments: DS.hasMany "comments", async: true
okToMerge: computedPromise "comments.[]", ->
@get("comments")
.then (comments) ->
comments.find (comment) ->
comment.get("speaker") is "rwjblue" &&
comment.get("comment") is "lgtm"
```

Aside from the infinite loop notification problem as mentioned in https://github.com/cibernox/ember-cpm/pull/132#issuecomment-170152050

There is another issue regarding different instances of an object sharing the same result state.
### The Reason

From the code at:

https://github.com/cibernox/ember-cpm/blob/master/addon/macros/computed-promise.js#L41

We see that both `pendingPromise` and `result` are declared outside the computed property, which means if you have something like:

``` coffeescript
issue1 = @store.find "issue-thread", 1
issue2 = @store.find "issue-thread", 2

issue1.get("okToMerge") # Call to start the promise
waitUntilResolve()
issue2.get("okToMerge") === issue1.get("okToMerge")
```

That is, even though we have two distinct instances of the `IssueThread`, they both share the `result` state... which is definitely a bug
### My Humble Suggestion

Please consider just putting `pendingPromise` and `result` directly into the object instance, i.e.:

``` javascript
return computed(...dependentKeys, function(key) {
if (!this[key + "PendingPromise"]) {
const promise = fn.call(this);
this[key + "PendingPromise"] = true;

Ember.RSVP.resolve(promise)
.then((promiseResult) => {
this[key + "Result"] = promiseResult;
pendingPromise = false;
this.notifyPropertyChange(key);
});
}

return this[key + "Result"];
});
```

Yes, this feels dirty, but this way, state is properly tied to each object instance, not to some closure shared by all instances of a factory. And we could always put in some `assert` to ensure the additional property names aren't colliding, and tell off the user if they are.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.