-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
[BUGFIX beta] Prevents autotracking ArrayProxy creation #17834
Conversation
35c5287
to
3cfbf95
Compare
cc @wagenet, this should fix the bug we found |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we certain that these two places are the only places that "consume" the array proxy? I haven't traced all the codepaths for the underlying mixins (MutableArray
, ArrayMixin
, etc)...
3cfbf95
to
6d3fd43
Compare
So the general contract for any Other than that, the one thing that requires us to add observers is adding an observer to the array proxy itself, since it then must start forwarding events. This is why the PR changes all uses to calling
|
6d3fd43
to
b9ec819
Compare
I'm pretty sure our app hits the problem in areas other than ArrayProxy. I'm working on getting more details. @wycats also seemed to think it was a larger issue. |
@wagenet yeah, it's definitely possible, if you have other cases we could definitely use them! I think lazily setting up the observers here is still a good change regardless, so our thinking was let's get this merged for now and keep finding more reproductions. If we find enough to suggest that this will be a major breaking issue, we'll have to rethink certain aspects of autotracking. |
I have verified that this does not fix all of the issues in my app. I'm investigating further. |
Yep, totally agree that this doesn't fix everything, but I think it's a good change regardless. Specifically, making ArrayProxy lazier on its own is a "nice to have"... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, i think @rwjblue mentioned this out of band as well, but we should fix Ember.addArrayObserver
to delegate; having ArrayProxy
not consume on addArrayObserver
seems like a mega-troll for users who run into it. It may not be used in EmberObserver
but I wouldn't want to bet on it not being used in apps.
packages/@ember/-internals/glimmer/tests/integration/components/tracked-test.js
Outdated
Show resolved
Hide resolved
I was actually mistaken about |
b9ec819
to
0017138
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❤️ 👍
@pzuraq - I think this change is still something we want to land, even though it isn't required to fix the infinite rendering issues that originally caused us to look at this. Would you mind rebasing? |
It looks like I'm running into this same error using |
@scottmessinger is this with the tracked properties feature flag turned on? And if so, does it work if the flag is disabled? |
@pzuraq I don't think so? How do I do that? I'm using the latest canary. Here's the features list I'm seeing: https://github.com/emberjs/ember.js/blob/master/FEATURES.md |
@pzuraq Yes! I do have it enabled -- sorry, took me a while to find it. Here's what I have:
|
Also, the infinite rendering is happening if I return a promise from a getter and then pass it to the https://github.com/tildeio/ember-async-await-helper component. That library doesn't use ObjectProxy, so it's possible my issue is caused by something else. |
For sure, if you could upload a reproduction that would be super helpful. This is definitely the kind of issue we're keeping our eyes out for since we're trying to land tracked properties relatively soon! |
Sure! What's the easiest way to do that these days? It doesn't look like ember twiddle is up to date. Would just a new ember app with octane be the best or is there anything faster? |
Yup, especially for canary bugs since ember-twiddle has never supported canary/canary-flags (maybe we can do some work on that in the near future..) An app repo would be perfect. |
@pzuraq Hopefully this will work: I made two failing test cases: scottmessinger@e349e96 It turns out the problem wasn't returning a PromiseProxy but returning null and then, later, a promise proxy. You might be wondering, "Why in the world would you ever do this?" Great question. In my app, I was finding this.args was undefined in the getter the first time it was was called. Later, they'd be populated. So, I just returned null if this.args was undefined. Later, when args was populated, I'd return the PromiseProxy or the promise. Is that helpful? |
@pzuraq Let me know if you need anything else or the failing test case above isn't helpful! |
Sorry, this is on my radar, I've just been super busy and haven't had a chance to dive in. I'll probably be able to get to this sometime next month |
@pzuraq No problem! Let me know if there's anything else I can do to be helpful!! |
0017138
to
1f67007
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you prefix the commit with [BUGFIX beta]
?
@@ -564,8 +565,10 @@ const ArrayMixin = Mixin.create(Enumerable, { | |||
@property {Boolean} hasArrayObservers | |||
@public | |||
*/ | |||
hasArrayObservers: nonEnumerableComputed(function() { | |||
return hasListeners(this, '@array:change') || hasListeners(this, '@array:before'); | |||
hasArrayObservers: descriptor({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don’t we also need to add enumerable: false? Also, is caching important here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, yes, I meant to do that!
For caching, I think it depends on how many times we expect folks to run addArrayObserver
and removeArrayObserver
, since nothing else really uses it in the ecosystem or the codebase. It seems like that's also a relatively uncommon thing, but we could also keep it as a CP if we're worried and use untrack
to access it and prevent the issue.
1f67007
to
d9f2943
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a test to packages/@ember/-internals/metal/tests/accessors/get_test.js
for the "mutate inside unknownProperty
" deprecation?
2f9b2f9
to
da96a73
Compare
This PR prevents an issue with immediate invalidation within the new autotracking transaction. ArrayProxy currently reads from one of its own properties, `hasArrayObservers`, and then immediately updates it with `notifyPropertyChange`. We avoid this by using a native descriptor instead of a computed, and not using `get()` to access it. This way, nothing is tracked during creation (even if it is mutated).
da96a73
to
03c776b
Compare
@@ -111,11 +111,11 @@ export default class ArrayProxy extends EmberObject { | |||
this._arrangedContentRevision = value(this._arrangedContentTag); | |||
} | |||
|
|||
this._addArrangedContentArrayObsever(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LOL @ this typo, I stared at this line for ~ 3 minutes trying to figure out why it was in the git diff 😝
This PR prevents an issue with immediate invalidation within the new
autotracking transaction. ArrayProxy currently reads from one of its
own properties,
hasArrayObservers
, and then immediately updates itwith
notifyPropertyChange
.We avoid this by using a native descriptor instead of a computed, and
not using
get()
to access it. This way, nothing is tracked duringcreation (even if it is mutated).
The original PR attempted to add array observers lazily, when the array was first accessed. However, tests in addons (such as Ember Data) were failing with this strategy. One issue was that adding observers to
length
wouldn't work, since there was no way to add the array observer when that occured. This strategy keeps the current semantics the same, and prevents the backtracking issue.Also updated the PR to deprecate in
unknownProperty
if this occurs again, since it could happen in existing code today.