Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

computedPromise has issues with proper state management #136

Open
foxnewsnetwork opened this issue Mar 2, 2016 · 1 comment
Open

computedPromise has issues with proper state management #136

foxnewsnetwork opened this issue Mar 2, 2016 · 1 comment

Comments

@foxnewsnetwork
Copy link

The Problem

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

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 #132 (comment)

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:

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.:

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.

@kellyselden
Copy link
Contributor

@foxnewsnetwork Can you try v3.0.0? computedPromise got a major refactor, and may have fixed your issue in the process.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants