-
-
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
Do not slice classNames
and classNameBindings
speculatively.
#14389
Conversation
The vast majority of the time these arrays are completely static on the prototype, there are relatively few instances where we actually need to slice them but we were speculatively doing this "just in case" you wanted it. This change does not remove the ability to have custom `classNames` / `classNameBindings` per instance, but it does make it so that folks wanting to do this would need to do `this.classNames.slice()` first. This avoids many extraneous array allocations, and just one more layer of wasted work during initial render.
Do we think we can get away with this? I suspect it would probably be considered a breaking change since the slice was added a while ago in response to this use case. If we think it's okay to make this change I would be happy to see this go though. However, if we can't, I have an alternative that I am working on. My plan is that we make these a getter and try to detect access them during construction (with some POST_INIT trick), and if they are accessed, we assume they are being mutated and returned a sliced version (only during init). I plan to apply this to a few things such as per-instance tagName, etc to emit optimized component templates. If we detect that any of these features are used, we can set a flag on the class indicating the component is unoptimizable and fallback to the generic template we have today. If that works out, we might be able to get the same performance improvements without the breaking change. |
@chancancode - Thank you for reviewing! Yes, I agree that this is a tad bit tricky, but I still think this is something that we can do. No capabilities are removed by this PR (the only use cases I have seen of this are already We have done this sort of thing before, so there is precedent. For example, we made helpers params / hash frozen objects during the 2.9 cycle for similar optimizations. |
Updated to ensure that |
c800c18
to
0224f81
Compare
Mutating objects on the prototype (which includes concatenated properties) is not good. This changes the functionality of concatenated properties to freeze the resulting array while in debug mode, to make it clear that mutating them without slicing first is not good.
As noted in the Ember v2.11 release notes, concatenated properties such as attributeBindings are frozen in debug builds. This means we cannot push directly onto the attributeBindings array without first copying it via slice. Without this change, users may see errors like this when the `attributeBindings.push()` call is made: Uncaught TypeError: Can't add property 2, object is not extensible References: emberjs/ember.js#14389 emberjs/ember.js#14601
As noted in the Ember v2.11 release notes, concatenated properties such as attributeBindings are frozen in debug builds. This means we cannot push directly onto the attributeBindings array without first copying it via slice. Without this change, users may see errors like this when the `attributeBindings.push()` call is made: Uncaught TypeError: Can't add property 2, object is not extensible References: emberjs/ember.js#14389 emberjs/ember.js#14601
As noted in the Ember v2.11 release notes, concatenated properties such as attributeBindings are frozen in debug builds. This means we cannot push directly onto the attributeBindings array without first copying it via slice. Without this change, users may see errors like this when the `attributeBindings.push()` call is made: Uncaught TypeError: Can't add property 2, object is not extensible References: emberjs/ember.js#14389 emberjs/ember.js#14601
As noted in the Ember v2.11 release notes, concatenated properties such as attributeBindings are frozen in debug builds. This means we cannot push directly onto the attributeBindings array without first copying it via slice. Without this change, users may see errors like this when the `attributeBindings.push()` call is made: Uncaught TypeError: Can't add property 2, object is not extensible References: emberjs/ember.js#14389 emberjs/ember.js#14601
The vast majority of the time these arrays are completely static on the prototype, there are relatively few instances where we actually need to slice them but we were speculatively doing this "just in case" you wanted it.
This change does not remove the ability to have custom
classNames
/classNameBindings
per instance, but it does make it so that folks wanting to do this would need to dothis.classNames.slice()
first.This avoids many extraneous array allocations, and one more layer of wasted work during initial render.