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

Avoid large objects allocations and reuse everthing #532

Merged
merged 2 commits into from
Apr 26, 2018

Conversation

DaniilSokolyuk
Copy link
Contributor

Main part of this PR
I propose to mark the old methods that do not take the TextWriter as obsolete, to avoid errors if it is overridden
@dustinsoftware @Daniel15

Copy link
Member

@dustinsoftware dustinsoftware left a comment

Choose a reason for hiding this comment

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

This looks good to me. Will do a bit of local testing before merging. :)

return string.Format(
"ReactDOM.hydrate({0}, document.getElementById({1}))",
base.GetComponentInitialiser(),
JsonConvert.SerializeObject(ContainerId, _configuration.JsonSerializerSettings) // SerializeObject accepts null settings
Copy link
Member

Choose a reason for hiding this comment

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

Huh. This change is surprising to me but looks correct... not sure why SerializeObject was called here before.

Copy link
Member

Choose a reason for hiding this comment

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

I think it was to ensure that characters are escaped as appropriate (eg. if your container ID has special characters in it). However, it's likely that most users are using the standard auto-generated container IDs, so this change is probably safe.

component.Setup(x => x.RenderHtml(false, false, null)).Returns("HTML");
component.Setup(x => x.RenderJavaScript()).Returns("JS");

component.Setup(x => x.RenderHtml(It.IsAny<TextWriter>(), false, false, null))
Copy link
Member

@dustinsoftware dustinsoftware Apr 16, 2018

Choose a reason for hiding this comment

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

Thanks for updating the tests. Can you add back a test for RenderHtml that doesn’t use a TextWriter to show that the existing method still works?

Edit: After working on this locally, I discovered that there are already tests that ensure RenderHtml still works as expected. The helper extensions now only use the TextWriter version, so this isn't an issue.

component.Setup(x => x.RenderHtml(It.IsAny<TextWriter>(), false, false, null))
.Callback((TextWriter writer, bool renderContainerOnly, bool renderServerOnly, Action<Exception, string, string> exceptionHandler) => writer.Write("HTML")).Verifiable();

component.Setup(x => x.RenderJavaScript(It.IsAny<TextWriter>())).Callback((TextWriter writer) => writer.Write("JS")).Verifiable();
Copy link
Member

Choose a reason for hiding this comment

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

What does .Verifiable() do?

Copy link
Contributor

@jslatts jslatts Apr 16, 2018

Choose a reason for hiding this comment

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

It lets you call component.verify() without arguments and will throw if any of the .Verifiable() mock configurations were not called. It is not needed if explicit verifications are used like they are in this test.

@dustinsoftware
Copy link
Member

dustinsoftware commented Apr 23, 2018

Ok! I got around to testing this and it looks good. However, I'd like to get some more concrete benchmarks documented before merging this in. On my workstation there was no noticeable speed or GC improvements with this change, but I'm unsure if the component and props are so small with my sample that it doesn't show. Edit: Yes, that was the problem. I tested on an object with 10,000 keys and saw a 50% reduction in allocated strings, see results below.

Here the tool I put together, based on BenchmarkDotNet... feel free to suggest a better code sample I can use to show the benefits of this change. I'll do some more testing and see what I can find out. My goal is to add this benchmark tool to this project so we can find other improvements in the render pipeline.

@dustinsoftware
Copy link
Member

Before this change:

BenchmarkDotNet=v0.10.14, OS=Windows 10.0.16299.371 (1709/FallCreatorsUpdate/Redstone3)
Intel Core i5-4570 CPU 3.20GHz (Haswell), 1 CPU, 4 logical and 4 physical cores
Frequency=3117782 Hz, Resolution=320.7408 ns, Timer=TSC
  [Host]     : .NET Framework 4.7 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2633.0
  DefaultJob : .NET Framework 4.7 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2633.0

Method Mean Error StdDev Gen 0 Gen 1 Allocated
HtmlHelperExtensions_React 50.56 ms 0.4835 ms 0.4286 ms 250.0000 62.5000 13.22 MB
Environment_CreateComponent 47.62 ms 0.4689 ms 0.4386 ms 250.0000 62.5000 9.78 MB

After:

BenchmarkDotNet=v0.10.14, OS=Windows 10.0.16299.371 (1709/FallCreatorsUpdate/Redstone3)
Intel Core i5-4570 CPU 3.20GHz (Haswell), 1 CPU, 4 logical and 4 physical cores
Frequency=3117782 Hz, Resolution=320.7408 ns, Timer=TSC
  [Host]     : .NET Framework 4.7 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2633.0
  DefaultJob : .NET Framework 4.7 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2633.0

Method Mean Error StdDev Gen 0 Gen 1 Allocated
HtmlHelperExtensions_React 46.21 ms 0.6098 ms 0.5704 ms 250.0000 125.0000 7.46 MB
Environment_CreateComponent 46.74 ms 0.5432 ms 0.5081 ms 250.0000 125.0000 9.18 MB

@dustinsoftware dustinsoftware merged commit 86115d7 into reactjs:master Apr 26, 2018
@dustinsoftware
Copy link
Member

@DaniilSokolyuk this has shipped in 3.4!

@DaniilSokolyuk
Copy link
Contributor Author

@dustinsoftware Thank you! 👍

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