-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Faster computeds #1841
Faster computeds #1841
Conversation
…gled up and could use further refactoring.
dependencyTracking[id] = trackingObj; | ||
trackingObj._order = _dependenciesCount++; | ||
trackingObj._version = target.getVersion(); | ||
dependentObservable.state = state; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to expose state
as part of the public API?
If not, perhaps this should be exposed via a Symbol
e.g. ko.computedStateSymbol = Symbol('computed_state')
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. It will be private-named by the minifier anyway, but I agree it would be better still to use a Symbol
, equivalent to how we do for ko.observable
.
FWIW, it looks good to me. If you merge it with the |
I'll take a detailed look at this when a get a chance (probably in a day or two). |
I've merged the tests into and run them on a few platforms. ✅ It looks like these performance patches have introduced no new errors. There are however some outstanding errors that have been around for a bit: PhantomJS 1.9.8 when used with jQueryThis looks to come from #1773
Firefox
IE 7 and 8
|
* Remove leading underscore from "state" properties, but use it for the "state" property itself. * Use "computed" instead of "dependentObservable" within the ko.computed code. * Slightly simplify inheriting from ko.subscribable. * Rename "needsEvaluation" to "isStale". * Remove items from "state" object that aren't used by prototype methods (writeFunction and options). * Use "notifySubscribers" within ko.computed instead of "notify" wrapper. * Make sure "read" and "write" functions aren't called with "this = state".
…unctions (from three to one).
I decided to do a bit of clean-up first and then tackle refactoring the disposal code. Overall, I'm really happy we're able to make this kind of improvement in Knockout. |
Incidentally, if we will be exposing the knockout/src/subscribables/observable.js Lines 1 to 2 in ac5f21b
var shouldUseSymbol = !DEBUG && typeof Symbol === 'function';
ko.utils.newSymbol = function (name) {
return shouldUseSymbol ? Symbol(name) : name;
} |
@brianmhunt That's exactly what I was thinking, and in fact I just implemented that simultaneously with your post :) Pushed as 8c1e65d |
0109347
to
b5d5d6d
Compare
Totally agree! Great point. Renamed to I'm not so sure about the |
You're absolutely right about the ease-of-reference. I was thinking In the debug builds though, I agree it would be better for the symbols to be strings — for the debugging tools. – on |
I've just pushed commit b5d5d6, which reduces How I've achieved this is mainly by factoring out the Some of these refactorings are a bit, well, unnatural. I tried only to restructure things in ways that either (a) improved readability or (b) make substantial measurable improvements to speed. Arguably it's good to split up If anyone objects to this commit (b5d5d6) please speak up! |
I'd strongly prefer to avoid exposing this in production builds. It's already possible to reach them when debugging a production build by using |
Totally. |
BTW thanks @mbest for your tidy-up, and for figuring out all the disposal stuff! This branch is ready to be merged as far as I'm concerned, and I'm hoping we can ship 3.4.0 very soon :) |
They don't need to be anonymous, and I didn't really have any particular reason for defining them that way. I've pushed a further commit to give them proper names. As for all the others (e.g., all the properties on |
👍 Excellent @SteveSanderson & @mbest I've merged |
Nice work all 👍 |
@SteveSanderson Yes, sorry – I didn't mean to suggest we do any wholesale changes to the naming conventions outside the scope of the issue at hand, just to keep it in mind for future. However for the two functions identified, and you've since updated, it seems like the naming convention may be valuable. |
Just wanted to chime in and report the fantastic speed increase I can see in my app testing with these improvements. It is certainly noticeable. Great work and thank you 👍 roll on 3.4.0 |
I made some minor adjustments to |
7f77e8c
to
b53978f
Compare
I reverted most of 7f77e8c because I realized that the compiler would merge the functions that way, eliminating the benefit of splitting it up in the first place. |
b53978f
to
d2ce361
Compare
I have given the latest version a whirl and I can report massive speed improvements across the board, particularly with |
Fantastic - it's merged then. Thanks @mbest for the code improvements and to everyone else for helping validate the design and checking the perf effects! |
Similar to #1840, this pull request improves the performance of
ko.computed
initialisation. It reduces the time taken to construct computed instances by about 50%, and perhaps more importantly, reduces the memory overhead to about half of what it was before.Like #1840, the approach is mainly to factor out all the closure-captured function instances and put them on the prototype instead.
Review notes
This change touches (or will touch) nearly every line in
ko.dependentObservable.js
, because it involves factoring out most of the logic insideko.computed
. That makes it a bit hard to review - sorry about that - couldn't avoid it! To make it a bit easier to review, I've broken it down into more commits than would be normal. But let me know if you suspect I might have unintentionally changed any behavior. Specs are all still passing.Compatibility
Like #1840, there should be no compatibility difference, except for scenarios where code does equality comparisons on methods (e.g.,
myComputed1.peek === myComputed2.peek
will always be true now). If anyone objects to this, please let us know! (I think we would do it anyway though)Not yet complete!
There's still quite a big, confusing mass of setup code relating to dispose handlers. I would like to clean this up further (both for perf, but mainly for readability) but am out of time for today. If anyone else wants to jump in here you'd be welcome :)