-
-
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
[Glimmer 2] "Backtracking re-render" is now an assertion #13948
Comments
FYI, we had some of these warnings in our app. Specifically, we updated some properties of a service in the It is very simple to fix this warning by scheduling the property change on the next run loop. It took me ~an hour to track down and fix all of the warnings in our (fairly large) app. Although this is technically a breaking change, I agree with your assessment even if it caused me some extra work. |
Fixes ``` Error: Assertion Failed: You modified activeStates.disabled twice in a single render. This was unreliable and slow in Ember 1.x and is no longer supported. See emberjs/ember.js#13948 for more details. ``` in Ember 2.9
@fivetanley improving the error message here sounds good. I know @krisselden and @stefanpenner has a workflow for tracking down these issues, maybe they can help give you some directions on this. |
@joukevandermaas run.next() is not a great fix for this error, though I understand if you are overwhelmed with these errors why you would go there. It is best to try to understand why the back flow of data is invalidating things that are already rendered. Likely if you set props on a service that could be injected onto any component, it increases the chances of that set invalidating something that was already rendered. In general, the pattern should be that set() is only used on internal state during rendering hooks, not tied to input or services and or set() is used on an event, input state should be settled by the time stuff renders. |
doing so cause performance issues, as glimmer2 in this case is informing "duplicate work is happening, you really don't want this if you want a performant app". Where previously, ember would absorb this, but result in heft performance penalty. We have some more knowledge sharing work todo here... Ultimately we believe this is a healthy path forward for apps. But we need to make sure everyone has the tools + knowledge available to benefit :) |
As a person who follows Ember goings on relatively closely (twitter, here on github, mailing lists, etc) this issue snuck on on me so I would suspect that this might catch others by surprise if it lands as part of Ember 2.10, particularly because the deprecation warning associated with it specifically states the behavior will be supported until 3.0. I don't believe I've seen it socialized anywhere that this behavior will not work in Glimmer 2 (although I may have simply missed it). |
yup, we need to improve some messaging / details here. |
I see this made it into the 2.10 release. Will this be mentioned in the 2.10 release blog post? |
This was not mentioned in the 2.10 blog post and took me by surprise since the deprecation warning previously said it would be supported until 3.0, as was mentioned above. |
I have a usage pattern that's affected by this. I'm sure the problem must be my usage pattern, and not this particular change, but I would love some input on what a good alternate usage pattern would be! Basically, I have a page that shows a filterable set of data, and to achieve this, I'm using an Ember computed value to filter the data based on the value of several query-params on the page. However, to prevent invalid inputs (eg not letters or numbers) from being added to query-params from user input, I have the following pattern: filteredModel: Ember.computed('model', /*list of individual query params*/, function(){
let model = this.get('model').filterBy('pdf.pdf_path.url'); //removes all records that don't have a pdf uploaded
this.get('queryParams').forEach((filter)=> { // for each possible filter
if ((this.get(filter).length > 0)) { //if the filter has content...
//guardian pattern to prevent invalid inputs
let valid = new RegExp('^[A-Za-z0-9 _]*[A-Za-z0-9][A-Za-z0-9 _]*$');
while (this.get(filter).length > 0 && !valid.test(this.get(filter))){
this.set(filter, this.get(filter).slice(0,-1));
}
//block of code where the model gets filtered
//...
//...
});
return model;
}), So basically, when I computed what the filtered model should look like, if any of the filter values have invalid characters in them, I strip off the last character until they become valid. Does anyone have a suggestion of a cleaner way to do validity-checking on these inputs? |
From the initial post, some hooks were mentioned:
Why are |
onChange should be triggered only by user input, otherwise ember color change triggers onChange event and it ends up with ember exception - double render - issue: emberjs/ember.js#13948
@BenjaminHorn @Blackening999 @Dhaulagiri @DingoEatingFuzz @Gaurav0 @GavinJoyce @Redsandro @TRMW @Turbo87 @aklkv @alidcastano @backspace @bdiz @bgentry @bjornharrtell @bryanhickerson @buschtoens @caseklim @cbou @chancancode @danaoira @daniel-de-wit @fivetanley @fotinakis @gabrielgrant @ghost @jakesjews @janmisek @joukevandermaas is this still an issue, perhaps we should close, what do you think? |
I fixed any instances of the error in my app. |
Anytime I’ve encountered this I’ve been able to rearrange things so that it wouldn’t happen anymore, so I think it’s okay to close. |
Yes, please close |
end of an era 😬 |
This comment has been minimized.
This comment has been minimized.
Sorry to bring up an old issue. Say for example I am rendering
and the error is I can fix the error by changing it to:
Similarly, if a class name binding is causing the problem I can change:
to
If I can silence the warning like this, why can't Ember handle it for me? Here is the demo code I was using: |
None of those things “fixes” the problem. It’s either that you switched to production mode, or there are bugs in the assertion/detection code. In any case, you need to fix the side that assigns/sets the value, not the side that consumes it. |
Ok. Thank you. I understand the backtracking problem outlined in this original post because it has an explicit But in my demo twiddle, there is no Edit That came out wrong, I mean to say there is no |
Hm, I'm not getting the error in the twiddle, what is the sequence of clicks I should do? |
Click open, and then click close. But the close button of the yielded child component, not the parent. |
I see, the problem is that during teardown, |
This addresses an issue of paths loading and one or more of the axes showing only tick 0, with all the paths connecting to it. This was working but a recent commit disconnected the update, as has happened several times before. Use CP dependencies to update the axis ticks and scale. draw-map.js : add to axisApi : cmNameAdd, makeMapChrName, axisIDAdd. axis-1d.js : added CPs : dataBlocksDomains, referenceBlock, blocksDomains, blocksDomain, blocksDomainEffect, domainEffect. models/block.js : add CP : featuresDomain. feature.js : add CP : valueOrdered. data/block.js : use cmNameAdd(). (viewed() may not be updating - trialling an added dependency and changed use of blockValues()). draw/axes-1d.hbs and axis-1d.hbs : commented-out display of values which may be changed during the render (refn emberjs/ember.js#13948) : axis.view, currentPosition.yDomain. Use blocksDomainEffect. utility-chromosome.js : factor copyChrData() out of chrData(); add cmNameAdd() based on draw-map.js:receiveChr(). frontend/app/ : 6e37a2f 223853 Sep 10 20:25 components/draw-map.js 62cdfc0 22369 Sep 10 21:12 components/draw/axis-1d.js 2b94ee2 24542 Sep 10 20:25 components/draw/block-adj.js 563096e 2943 Sep 10 16:51 mixins/axis-position.js 06c02ae 6638 Sep 10 18:30 models/block.js 930fc67 1021 Sep 9 16:59 models/feature.js 4e7d202 14286 Sep 10 15:14 services/data/block.js cf7716e 356 Sep 10 17:24 templates/components/draw/axes-1d.hbs ed752af 578 Sep 10 18:42 templates/components/draw/axis-1d.hbs 8c18360 3946 Sep 10 15:36 utils/utility-chromosome.js added : 998f0c9 1623 Sep 10 18:30 utils/interval-calcs.js
> Backtracking re-render refers to a scenario where, in the middle of the rendering process, you have modified something that has already been rendered. See more details from the Ember team here emberjs/ember.js#13948. We call _updateInput from init. _updateInput triggers onChangeInput which mutates a date that was given to future-date-input just a moment ago and a rendering cycle wasn't finished yet.
The `errors.unknownProperty` accessor would initialise the property on every attempt to access. If this happens more than once during a render cycle, newer Ember will complain since it is highly inefficient. See emberjs/ember.js#13948 for more details. Also removes the use of the `getOwner` polyfill, which was added natively to `Ember.getOwner` in Ember 2.3. Lastly updates the dependency on `ember-cli-babel` to be in line with newer Ember CLI requirements.
We are trying to upgrade ember in our app from 2.8 to 2.12 and facing this error throughout our fairly large application (100+ routes and 450+ components). We tried to fix this issue, wherever it is captured, but still there are some uncovered areas where this "modified 'x' twice" might present. My understanding is these backtracking will be detected and error is thrown only in debug builds. In production, the detection will not happen, so no errors will be thrown. Until v2.10, we were doing the backtracking rerender in prod and now that is not happening in the v2.12 prod. My question is - will there be any unexpected bugs in the way the application code works as we are not doing backtracking rerender in production? |
Backtracking re-render refers to a scenario where, in the middle of the rendering process, you have modified something that has already been rendered.
For example:
As you can see, by the time the
foo-bar
component is instantiated and rendered, we have already used the valuefoo
from the parent context to populate the{{foo}}
curly. However, in its constructor, it was trying to modify the same value, hence. "backtracking".This is a pretty extreme example, but it illustrates the problem. Besides
init
,didInitAttrs
,didReceiveAttrs
,willInsertElement
andwillRender
also happens synchronously during the rendering process. Additionally, backtracking is often an issue arising from the behavior of two-way bound properties.This behavior has always been unreliable, but was partially supported with a deprecation (since Ember 1.13):
Since 1.13, Ember supported this by immediately doing a second re-render when backtracking was detected (and then repeating until the system stabilizes). This strategy itself could be a source of performance problems. In extreme cases, this could cause an infinite loop.
In Glimmer 2, while the extra re-render is relatively cheap, the extra book-keeping to detect a backtracking
set
is not. One of the wins of the Glimmer 2 system is that it does not need to eagerly setup observers to track changes. Further, certain optimizations in Glimmer 2 allows the system to skip traversing subtrees when it knows nothing within it has changed.Together, these factors mean that we can not readily detect these backtracking
set
s (or whether something was "already rendered" or not) without doing a large amount of extra book-keeping and intentionally defeating these optimizations.We already wrote the code to support this, but due to the already unreliable nature of the feature, and the (very significant) book-keeping costs, we are hesitant to automatically enable them for everyone without knowing whether it is still needed.
As a compromise, we currently only perform the detection in development mode and turned the deprecation message into a development-mode assertion (hard error). In production mode, the detection code is stripped and backtracking will not work.
We have kept the facility to support this feature (without the assertion) in the codebase behind a second feature flag. The code is being tested continuously on CI, however, is disabled by default until we have enough usage information to determine next steps.
If you believe you have usage patterns that are affected by this, please provide as much detail about your scenario as possible below. It is very possible that there can be alternatives and/or targeted solutions we can use that do not require a wholesale change to the engine. Therefore, it would be helpful if you provide background information and context about your usage instead of just showing us small code snippets from your codebase.
The text was updated successfully, but these errors were encountered: