-
Notifications
You must be signed in to change notification settings - Fork 47.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
Optimize _bindAutoBindMethods #2895
Comments
cc @sebmarkbage. We were talking about changing the autobinding recently. He might have some insight here (especially in context of ES6 classes) |
The idea is to move to an explicit binding model using ES6 classes + maybe property initializers. This lets you choses whether to bind at construction time or as they're used in render according to your optimizations. Maybe there is a way we could change the optimization for server side render but I doubt it since in theory you'd need to bind it at least once even on the server. It's possible to call a callback in componentWillMount. I would also suggest that you try a different strategy for benchmarking. Profiling tools tend to exaggerate small methods that gets called a lot. If you comment out the call to |
WRT to the profiling manually: that's what the In ReactCompositeComponent#mountComponent: var startTime = process.hrtime();
this._bindAutoBindMethods();
var diff = process.hrtime(startTime);
bindTime += (diff[0] * 1e9 + diff[1]); Printing out I will try removing the method to see how it effects total rendering time. I was concerned before that the render would break if this was removed for instance with |
Yeah, unfortunately this breaks some of our components when testing without calling |
@mridgway Just to be safe, have you considered the cost of calling |
You could also maybe try calling _bindAutoBindMethods twice to see what that adds? |
You're right:
So altogether it looks like the We're still trying to figure out why our render times are so high though. |
No matter how I measure it, Migrating to ES6 components helps for our custom components, but not for the built-in components which use It seems like there are two ways to mitigate this issue:
|
Migrating to ES6, where possible, seems better. It's hard to justify optimizing a feature that is "not the future". We should increase the priority of migrating the built-in components to ES6 if we're really going to get a 15% perf boost on SSR. |
@JSFB Not too hard to justify it when everyone uses it… but I don't know how to make autobinding faster. |
With |
Yea, not really hard to justify at all. We're still talking about server-side here right? Perhaps there's something we can do so we don't actually create all the bound functions upfront? Maybe have placeholder functions which lookup the real function and use |
@mridgway Can you try requiring 'react/dist/react.min.js' instead of the main React module as you're currently doing and compare? |
(Wondering if this is #812.) |
I don't think it is related to #812, since both tests are hitting the |
Here's a build from #3615: https://s3.amazonaws.com/uploads.hipchat.com/6574/26709/Ojl4jYZgCmwTdo1/react.min.js And one with the call to bindAutoBindMethods removed: |
Ran the test with the above files and still seeing about 25% difference. The changes that I made for the benchmark are here: mridgway/flux-example@0d6a228 Ran it a few times to confirm, but here's the smallest margin of difference that I found: $ node bench-chat.js
React 558 ops/sec ±5.06%
ReactOpt 698 ops/sec ±1.87% |
Okay. I'm having trouble getting that running locally – it complains it can't find fluxible-router and I haven't figured out the right incantation of install/link/etc to make it work. |
Sorry, let me pull this out and simplify. |
Ok, you should have better luck with this repo: https://github.com/mridgway/react-perf Note: the minified builds seem to break if I don't use NODE_ENV=production for some reason. |
Still failing to require fluxible-router here: https://github.com/mridgway/react-perf/blob/e8e0048d5153b3c2acd834b44ff9fb88c17b0cfd/chat/components/ThreadSection.jsx#L23 |
Ugh, so sorry. This is what happens when you globally link something. I pushed changes that removes that dependency. |
Got it. Not seeing 25%, but definitely some difference – like 10% with NODE_ENV=production:
|
I think it's important to note that even if you drop |
The typical use case for needing the autobinding is for event handlers which usually only get fired on the client. It would be more optimal to bind the methods on |
Looks like 0.13 started autobinding getDOMNode where we didn't previously, which is almost certainly unintentional on our part. :( |
Whoa, I noticed this in some of my benchmarks as well but thought it was an outlier. Have you tried with Chrome's high resolution timers? Sometimes frequently called functions get an unfair share of the blame. |
@jordwalke This isn't with a profiler; this is with normal React and with autobinding commented out. |
With #3801 merged in, would you be open to a PR to migrate internal components to ES6 classes instead of |
I think so. Let's do the plain ES3 "class" syntax for now until we figure out whether we want to use loose mode, etc. in babel. |
Closing as internals have removed usage of |
We are running into some performance issues using React on the server side. In large component trees, we are finding that render time increases linearly. In our case, we are seeing render times over 80ms for a relatively simple page (112 components). During profiling we have found that the
_bindAutoBindMethods
is showing up at the top of our trace:I went in and added hrtime() calls inside
_bindAutoBindMethods
to see how much time was contributing to the rendering, and found that over 23ms was used just within this method. This may not seem like a lot, but this has pretty dramatic effect on throughput when the server is rendering synchronously.Is there a way to optimize this so that binding happens lazily? On the server, many of the methods may not even be called (event handlers, lifecycle events,
getDOMNode
, etc.).The text was updated successfully, but these errors were encountered: