Skip to content

Data: Avoid ES5 defineProperty for speed #1668

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

Closed
wants to merge 1 commit into from

Conversation

jbedard
Copy link
Contributor

@jbedard jbedard commented Sep 27, 2014

As discussed in http://bugs.jquery.com/ticket/14839, removing the use of definePropert(y|ies) brings the jQuery2 data initialization up to speed with jQuery1 for DOM nodes. For non nodes this also switches from defineProperties to defineProperty which is a bit faster, saves an object and saves some bytes.

@gibson042 this has the changed you suggested in jbedard@d44885b

@rwaldron
Copy link
Member

Thanks for contributing! There is an existing patch that will change how data is created and managed #1428

@rwaldron rwaldron closed this Sep 28, 2014
@jbedard
Copy link
Contributor Author

jbedard commented Sep 28, 2014

I thought @gibson042 wanted this in?

#1428 will be great, but will it make it into the next release? And will this change (avoiding defineProperty) make it into #1428?

@rwaldron
Copy link
Member

Sorry, I was mobile when I was looking at this and looked right past that part.

@rwaldron rwaldron reopened this Sep 28, 2014
@markelog
Copy link
Member

@jbedard would you mind post here a resulting jsperf? With and without your changes that is?

@rwaldron
Copy link
Member

Here's an old one just comparing assignment/defineProperties/defineProperty: http://jsperf.com/v1-v2-data

This isn't an accurate representation of the operations that jQuery 1 and 2 are doing for data. That op happens only once per object for any object that store arbitrary data.

http://jsperf.com/remove-dp is attempting to remove nodes that were never attached, which will affect the result. http://jsperf.com/remove-dp/2 is closer, but also measuring the cost of jQuery(elem.cloneNode(true))

I was working on a revision but got blocked by jsperf's spam filter mechanism.

@jbedard
Copy link
Contributor Author

jbedard commented Sep 28, 2014

But that is what we want to measure, only the first data operation that happens once per object, that is the only thing improved by this change.

The clone/remove was mainly to show that this change has an effect on overall performance when performing a standard operation such as constructing a DOM and adding some data (although .append is probably better then.remove after that...). Just showing that .data is faster then before (which http://jsperf.com/v1-v2-data sort of does) doesn't really put it into perspective.

I've hit that jsperf spam issue as well recently :(

@rwaldron
Copy link
Member

Comparing the measurement of current and patched .data("key", value) for a large number of elements should be sufficient. This is what I was putting together when I got blocked :\

@dmethvin
Copy link
Member

@jbedard or @rwaldron do you want to do a jsperf for this?

@jbedard
Copy link
Contributor Author

jbedard commented Oct 14, 2014

Did you want something other then the jsperfs mentioned above? I think those show the advantage of this change quite well...

@rwaldron
Copy link
Member

@dmethvin landing this will have shave some time off, but nothing like the perfs shown above.

http://jsperf.com/jquery-setting-initial-data

(compares 1, 2, and this patch)

@jbedard
Copy link
Contributor Author

jbedard commented Oct 17, 2014

If you only want to measure the first call to .data, nothing else, then I think http://jsperf.com/jquery-setting-initial-data/2 is a bit better (avoids .children). It might also be good to compare against the latest master instead of 2.1 to avoid the recently fixed chrome perf issue: http://jsperf.com/jquery-setting-initial-data/3

Seems well worth it to me. It improves in every browser, in every jsperf, and reduces size...

@rwaldron
Copy link
Member

@dmethvin I think this is reasonable to land.

@dmethvin
Copy link
Member

Awesome, thanks for the work on this everyone!

@jdalton
Copy link
Member

jdalton commented Oct 23, 2014

I'll pile on bad news, at the moment it looks like ES6 may actually be making Object.defineProperties and Object.create slower by following the lead of Object.assign to hold on to the first error thrown and continue executing which may hurt perf in much the same way as try-catch and complicate inlining.

@rwaldron
Copy link
Member

@jdalton this is not the appropriate place to report ES6 specification issues. Please file here: https://bugs.ecmascript.org/enter_bug.cgi?product=Draft%20for%206th%20Edition

@jdalton
Copy link
Member

jdalton commented Oct 23, 2014

Yap, I'm aware of where to file spec bugs. Just giving a heads up that the perf forecast for these methods at the moment isn't getting better.

@rwaldron
Copy link
Member

But if you file a bug, the issue will at least get attention before ES6 ships. You should also loop in @bterlson on spec-responsible performance issues.

@bterlson
Copy link

@rwaldron: not to worry, we're on it (though no promises there will be any change to the current draft ofc)

@rwaldron
Copy link
Member

@bterlson is it worth bringing up at the next meeting?

@bterlson
Copy link

@rwaldron Yep, worth discussing.

@anba
Copy link

anba commented Oct 24, 2014

If the new exception handling in Object.{assign, create, defineProperties, freeze, isFrozen, isSealed, seal} is considered to be too harmful for performance, exception behaviour in for-in and for-of most likely also needs to be changed.

@bterlson
Copy link

@anba yeah, good to discuss those too. I don't think for-in/for-of semantics will change since their behavior is well motivated (and long-discussed), but the Object API changes seem less well motivated.

@jdalton
Copy link
Member

jdalton commented Nov 21, 2014

Rock y'all, the issue raised earlier has been resolved by the TC39.

@dmethvin
Copy link
Member

dmethvin commented Dec 4, 2014

I am inclined to land this as-is for 3.0 but want to note here that with gh-1886 and deprecating plain objects we should be able to always use the expando approach at some point. Thoughts?

@gibson042
Copy link
Member

We have always taken pains to prevent the property required by .data from causing problems... even the compat branch uses toJSON to hide it since Object.defineProperty isn't guaranteed:

jquery/src/data.js

Lines 97 to 99 in a4e31a8

// Avoid exposing jQuery metadata on plain JS objects when the object
// is serialized using JSON.stringify
cache[ id ] = isNode ? {} : { toJSON: jQuery.noop };

@dmethvin
Copy link
Member

That toJSON hack was added specifically to support the now-defunct jquery-datalink plugin, and it turned out that wasn't enough to allow it to be Object.observe. I'd be okay with removing that in the 3.0 compat branch for symmetry. Our release notes can provide enough info to allow people to make their own fixes for these edge cases.

@dmethvin
Copy link
Member

Another thought @gibson042, what if we use the same { toJSON: jQuery.noop } initial object for master? That gives us the same behavior across both.

@gibson042
Copy link
Member

That sounds good.

@jbedard
Copy link
Contributor Author

jbedard commented Dec 18, 2014

Is the toJSON/noop something I should do in this PR?

@dmethvin
Copy link
Member

@jbedard oh that would be awesome. We're preoccupied with a release the last couple of days. You got the gist of it right? We want the behavior identical in the two branches. I think we're already set for a unit test, you just gotta put it back. 😈

@jbedard
Copy link
Contributor Author

jbedard commented Dec 18, 2014

I'll give it a shot, hopefully tonight.

But now that I look at how 1.x does it... In 1.x .data on an object actually puts the data on the object, so the data object can have the toJSON put on it. But in 2.x putting data on an object works the same as elements where only the uid is put onto the object. We could change 2.x to be more like 1.x but that makes this a bigger change, and starts to cross with #1428...

@rwaldron
Copy link
Member

Hm. Looks like this was never landed: #1428

@rwaldron
Copy link
Member

As soon as this lands, I will rebase the other.

@jbedard
Copy link
Contributor Author

jbedard commented Dec 18, 2014

If #1428 will land I think that is a better place to introduce the toJSON. Should this PR go back to defineProp for now though?

@dmethvin
Copy link
Member

I guess so...sorry for the confusion @jbedard!

@jbedard jbedard force-pushed the 14839-jq2-dp branch 4 times, most recently from 364fd97 to c04c239 Compare December 18, 2014 17:08
@jbedard
Copy link
Contributor Author

jbedard commented Dec 18, 2014

Updated to use defineProp again for non nodes.

The no-defineProp commit for reference: jbedard@94ddf72

It would be great if #1428 could land as well to remove defineProp. I think that will also make compat/master more aligned? Might even be able to port the entire 2.x Data to compat once it doesn't use any ES5..?

@rwaldron
Copy link
Member

I rebased #1428 earlier today, so should be good to go

@timmywil
Copy link
Member

timmywil commented Mar 4, 2015

It's been a while. Is everyone ok if we land this?

@dmethvin
Copy link
Member

dmethvin commented Mar 4, 2015

Looks like @jbedard needs to re-sign the CLA with the email he used for the commit, but otherwise YES, let's get this puppy landed! 🐶

@jbedard
Copy link
Contributor Author

jbedard commented Mar 4, 2015

I've resigned with the email of the commit. Does @jquerybot need something to trigger it?

@arthurvr
Copy link
Member

arthurvr commented Mar 4, 2015

@jbedard Looks alright. Thanks! The bot doesn't have the ability to re-check PRs yet. (jquery/jquery-license#2)

@timmywil timmywil closed this in 95fb798 Mar 4, 2015
@rwaldron
Copy link
Member

rwaldron commented Mar 4, 2015

As promised, data-as-expando has been rebased

@rwaldron
Copy link
Member

rwaldron commented Mar 4, 2015

Hm. Looks like I lost something there. Hold the line please.

markelog pushed a commit that referenced this pull request Nov 10, 2015
@lock lock bot locked as resolved and limited conversation to collaborators Jan 19, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Development

Successfully merging this pull request may close these issues.