Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

perf(ngForm,ngModel): move initial addClass to the compile phase #8268

Closed
wants to merge 1 commit into from

Conversation

jbedard
Copy link
Contributor

@jbedard jbedard commented Jul 19, 2014

Other then moving from link to compile time the only difference (which unit tests didn't seem to care about) is that $animate.addClass(VALID_CLASS) and $animate.removeClass(INVALID_CLASS) are no longer called at link time since VALID_CLASS is added at compile and INVALID_CLASS shouldn't exist. If anyone depends on the initial animation calls or on the .removeClass(INVALID_CLASS) then this change won't work, at least in its current form...

@mary-poppins
Copy link

Thanks for the PR! Please check the items below to help us merge this faster. See the contributing docs for more information.

  • Uses the issue template (#8268)

If you need to make changes to your pull request, you can update the commit with git commit --amend.
Then, update the pull request with git push -f.

Thanks again for your help!

@caitp
Copy link
Contributor

caitp commented Jul 19, 2014

what exactly is the performance benefit of this? this is unclear to me

@jbedard
Copy link
Contributor Author

jbedard commented Jul 19, 2014

If a form or model is linked more then once it only adds the classes once at compile time (before cloning the element). Or am I missing something that makes this case different then other directives?

My use case is ng-model within ng-repeat, such as a list of items with a checkbox each...

@jbedard jbedard added cla: yes and removed cla: no labels Jul 19, 2014
@caitp
Copy link
Contributor

caitp commented Jul 20, 2014

right but, is something happening that you're not expecting to happen? adding/removing classes isn't a particularly expensive operation usually, so I'm wondering if you're really noticing this

@caitp caitp closed this Jul 20, 2014
@caitp caitp reopened this Jul 20, 2014
@caitp
Copy link
Contributor

caitp commented Jul 20, 2014

oops, didn't mean to close that

@jbedard
Copy link
Contributor Author

jbedard commented Jul 20, 2014

I think adding/removing classes is particularly expensive since it touches the DOM, and especially when it modifies the DOM. If it is done at compile time then it is done once and cloned where at link time it is done N times. This is basically what @IgorMinar has been doing to many directives, however this removes 3 calls to add/removeClass per link instead of just 1, but with the potential side effect of not going through $animate at link time (for 2/3 of the calls).

In the plunker below the NgModelController is about 25% of the bootstrapping, and half that is calling add/remove class 3 times...

http://plnkr.co/edit/kJWdsdy1NXjifSJOh21N?p=preview

@caitp
Copy link
Contributor

caitp commented Jul 20, 2014

I think adding/removing classes is particularly expensive since it touches the DOM

Classes aren't being added/removed all that frequently, so this is much less of a hit than it would be otherwise. Even in a list of 2000 form controls, it's pretty negligible.

Even when it comes to bootstrap time, I'm not sure that this is a real bottleneck in any real application --- I may be wrong, but I'd need to see proof to come to that conclusion. I think if it is a significant bottleneck, the application design probably needs to be re-worked, because it really shouldn't be.

Anyways, I'm pretty sure this is not right, but see what matias or igor think about it, really.

@jbedard
Copy link
Contributor Author

jbedard commented Jul 20, 2014

Does the plunker not show add/removeClass being 10%+ of the link time? I thought that was pretty significant for something that can easily be avoided...

Do you have an example of how an app such as the plunker example can be re-worked to avoid this? Or do you mean 2000 checkboxes is just bad UI? (Which I'd agree with, but that much data is rare enough in my case so it wouldn't be worth changing the UI.)

@jbedard
Copy link
Contributor Author

jbedard commented Jul 20, 2014

Note sure where your last comment went with the chrome screenshot, but I keep getting 10%+ of time being spent in add/removeClass and it seems fairly consistent across browsers (chrome/ff/ie) when profiling...

(Note that the 15% in NgModelController is 15/57% spent within angular)
perf

@Narretz Narretz added this to the Backlog milestone Jul 21, 2014
@btford btford removed the gh: PR label Aug 20, 2014
@IgorMinar IgorMinar modified the milestones: 1.3.0-rc.2, Backlog Sep 8, 2014
@IgorMinar IgorMinar self-assigned this Sep 8, 2014
@@ -410,7 +406,10 @@ var formDirectiveFactory = function(isNgForm) {
name: 'form',
restrict: isNgForm ? 'EAC' : 'E',
controller: FormController,
compile: function() {
compile: function(formElement) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

name anonymous fns

@IgorMinar
Copy link
Contributor

@caitp I think that for ngModel used in a repeater this change could be significant.

I'll review this and get it in as part of rc2

@jbedard
Copy link
Contributor Author

jbedard commented Sep 8, 2014

I've added the compile/link function names.

compile: function() {
compile: function ngFormCompile(formElement) {
// Setup initial state of the control
formElement.addClass(PRISTINE_CLASS + ' ' + VALID_CLASS);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do addClass(PRISTINE_CLASS).addClass(VALID_CLASS) in order to avoid extra string concat and splitting

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Performance wise I assume the extra string concat here is actually better because each addClass will do split+forEach+regex+get/setAttribute. But this is compile time so I don't think it matters much, and calling addClass twice looks more readable so I'll go ahead with that for now...

@jbedard
Copy link
Contributor Author

jbedard commented Sep 27, 2014

@IgorMinar I've made the suggested changes to the addClass lines.

@IgorMinar
Copy link
Contributor

can you rebase this on top of master please? it looks good otherwise.

@jbedard jbedard force-pushed the form-model-compile branch 3 times, most recently from e8d176e to effc9dd Compare September 30, 2014 03:34
@jbedard
Copy link
Contributor Author

jbedard commented Sep 30, 2014

Rebased.

Note that in the rebase I added a .hasClass in the new addSetValidityMethod to ensure the classCache is correctly initialized. This could probably be changed to just true but I thought I'd do .hasClass for now just in case something else between compile and addSetValidityMethod changes the state. I found this .hasClass was about ~1% of the link time, where the replaced .addClasss were ~5-6%.

@IgorMinar
Copy link
Contributor

merged. thanks

@IgorMinar IgorMinar closed this in b1ee538 Oct 1, 2014
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants