Skip to content
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

perf: remove object spreading #423

Merged
merged 2 commits into from
Jul 28, 2019

Conversation

baldurh
Copy link
Contributor

@baldurh baldurh commented Jul 24, 2019

Description

I replaced all instances of the object spread operator with Object.assign. The results are quite remarkable:

Benchmarks in ms. 100,000 iterations

before after change
responsive 1652.000 1104.215 -33.16%
responsive with fixed height 1373.051 886.121 -35.46%
responsive with aspect ratio 1862.155 1267.419 -31.94%
fixed width 1347.304 867.349 -35.62%
fixed width with quality 1420.417 908.058 -36.07%
fixed width with dpr quality disabled 1305.567 872.474 -33.17%
fixed width with aspect ratio 1326.964 861.080 -35.11%

Flamegraph before
Flamegraph after

@baldurh baldurh force-pushed the remove-object-spreading branch from be85caf to 58f3f91 Compare July 24, 2019 21:42
.gitignore Outdated
@@ -3,3 +3,4 @@ npm-debug.log
es
lib
node_modules
.clinic
Copy link
Contributor

Choose a reason for hiding this comment

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

We'd rather not have non-package-related exclusions checked into source control. Directories and files can be ignored locally (and not checked into source control) by moving this line to .git/info/exclude. This command will do it for you: echo .clinic >> .git/info/exclude

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Roger. Fixed!

@frederickfogerty
Copy link
Contributor

Thanks again @baldurh! LGTM once that .gitignore change is fixed 👍

@baldurh baldurh force-pushed the remove-object-spreading branch from 58f3f91 to e469268 Compare July 25, 2019 14:27
Copy link
Contributor

@frederickfogerty frederickfogerty left a comment

Choose a reason for hiding this comment

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

LGTM 👍

@frederickfogerty
Copy link
Contributor

Food for thought here - in Chrome 76+, spread is actually faster than Object.assign 🤷‍♀️

image
Source: https://jsperf.com/object-assign-vs-spreading

@baldurh
Copy link
Contributor Author

baldurh commented Jul 25, 2019

Food for thought here - in Chrome 76+, spread is actually faster than Object.assign 🤷‍♀️

Wow that’s super interesting. We definitely have to take that into account. I ran the benchmarks on node 12 and Object.assign is still faster than object spreading. Chrome 76 uses V8 7.6 while Node 12 is still at 7.4 so I guess that’s the reason. So I guess the question is: Do we want to make this faster for the latest Chrome browsers or everything else, including all Node servers (since none of them are running V8 7.6 yet)? Node servers will also probably not be using the latest V8 for a while even if the latest version of Node has it.

@frederickfogerty
Copy link
Contributor

Pulling in @jayeb to answer this from imgix's perspective. From my perspective, it's a tough call as there's no clear answer. I think we should accept this change as it is such a significant improvement, but aim to remove this in about a year's time (this could be put in a comment).

@jayeb
Copy link

jayeb commented Jul 26, 2019

I may be off-base here, but it seems to me that the performance of the spread operator in Chrome is mostly irrelevant--if this code is running in a browser, it's almost certainly going to be the Babel-compiled version, right? And since the compiled version isn't using the spread operator directly, it's kind of a moot point. This PR looks like an obvious win to me, but maybe I'm missing something.

@baldurh
Copy link
Contributor Author

baldurh commented Jul 26, 2019

I may be off-base here, but it seems to me that the performance of the spread operator in Chrome is mostly irrelevant--if this code is running in a browser, it's almost certainly going to be the Babel-compiled version, right? And since the compiled version isn't using the spread operator directly, it's kind of a moot point. This PR looks like an obvious win to me, but maybe I'm missing something.

@jayeb Yes you’re absolutely right. I realised this also this morning but hadn’t gotten around to mention it 😄 So babel transpiles the spread operator to a function looping over the props of the object being spread. So that’s going to be slow in any environment 🙈

Copy link
Contributor

@sherwinski sherwinski left a comment

Choose a reason for hiding this comment

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

This gets a 👍 from me as well. Based on the conversation, it seems like Object.assign is the way we want to go here. Unless anyone has objections to wait, I'll merge today.

@sherwinski sherwinski merged commit 29b25d5 into imgix:master Jul 28, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants