-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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] Entangle Errors.errorsFor properly #7273
Conversation
Asset Size Report for 76316bd IE11 Builds The size of the library EmberData has increased by 30.0 B (37.0 B compressed) which exceeds the failure threshold of 15 bytes.WarningsThe uncompressed size of the package @ember-data/model has increased by 30.0 B. Changeset
Full Asset Analysis (IE11)
Modern Builds The size of the library EmberData has increased by 30.0 B (37.0 B compressed) which exceeds the failure threshold of 15 bytes.WarningsThe uncompressed size of the package @ember-data/model has increased by 30.0 B. Changeset
Full Asset Analysis (Modern)
Modern Builds (No Rollup) EmberData increased by 30.0 B uncompressed but decreased by 33.0 B compressedWarningsThe uncompressed size of the package @ember-data/model has increased by 30.0 B. Changeset
Full Asset Analysis (Modern)
|
Performance Report for 76316bd Relationship Analysis
|
We recently made some changes to the way arrays get consumed when autotracking in Ember - specifically, whenever an array is return from `Ember.get`, `@computed`, or `@tracked`, we track that array for changes in the future. Previously, we also tracked it if it was an _EmberArray_. This check was a bit redundant, and costly, so we removed it and now only do it for native arrays. The reason this is generally safe is that non-native EmberArrays usually have a contract - you must access the state of the array via `objectAt`, and you must update via `pushObject`, `popObject`, etc. The array is consumed when using `objectAt`, so theres no need to do it eagerly in `Ember.get` (and penalize all other object access). The `Errors` class is a bit of a special case, because it adds additonal capabilities - the `errorsFor` method, which returns a subset of errors in the array. This info is accessed via the `errorsFor()` method, which does not consume the array proxy at all. So, previously, if a user did something like: ```js model.errors.errorsFor(field).map(error => error.message); ``` When `model.errors` was accessed, it was a `@computed` property, and it consumed the entire array proxy. Later on, when the user goes to add an error, it adds the error to the main array _and_ the subarray returned by `errorsFor()`, and dirties both, so the user's code is called again and updates properly. With the recent changes, that doesn't happen anymore. Since `errorsFor` returns a native array (with prototype extensions enabled), `map` does not use `objectAt` internally either. So, there is nothing that is properly consuming the array. This PR adds the consumption manually. In the future, we can likely add a primitive that allows Errors to create and manually manage tags, or it can use something along the lines of a TrackedArray for these errors instead.
f985d5e
to
76316bd
Compare
@pzuraq thanks a bunch for the fix! Can you point me to where this got changed in ember so I can track what kind of backport needs to happen |
@igorT this issue appeared in Ember 3.20.4. Can this fix be backported to [email protected]? |
@andreyfel yup, will do that as part of the release process |
ember-data contains the fix for the bug: emberjs/data#7273
We recently made some changes to the way arrays get consumed when
autotracking in Ember - specifically, whenever an array is return from
Ember.get
,@computed
, or@tracked
, we track that array for changesin the future. Previously, we also tracked it if it was an EmberArray.
This check was a bit redundant, and costly, so we removed it and now
only do it for native arrays.
The reason this is generally safe is that non-native EmberArrays usually
have a contract - you must access the state of the array via
objectAt
,and you must update via
pushObject
,popObject
, etc. The array isconsumed when using
objectAt
, so theres no need to do it eagerly inEmber.get
(and penalize all other object access).The
Errors
class is a bit of a special case, because it adds additonalcapabilities - the
errorsFor
method, which returns a subset of errorsin the array. This info is accessed via the
errorsFor()
method, whichdoes not consume the array proxy at all. So, previously, if a user did
something like:
When
model.errors
was accessed, it was a@computed
property, and itconsumed the entire array proxy. Later on, when the user goes to add an
error, it adds the error to the main array and the subarray returned
by
errorsFor()
, and dirties both, so the user's code is called againand updates properly.
With the recent changes, that doesn't happen anymore. Since
errorsFor
returns a native array (with prototype extensions enabled),
map
doesnot use
objectAt
internally either. So, there is nothing that isproperly consuming the array.
This PR adds the consumption manually. In the future, we can likely add
a primitive that allows Errors to create and manually manage tags, or it
can use something along the lines of a TrackedArray for these errors
instead.