Skip to content

Commit e551617

Browse files
performance improvements
1 parent fcb418e commit e551617

File tree

5 files changed

+83
-51
lines changed

5 files changed

+83
-51
lines changed

src/React.AspNet/ActionHtmlString.cs

+7-12
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
using System.IO;
1212

1313
#if LEGACYASPNET
14-
using System.Text;
1514
using System.Web;
15+
using React.Core;
1616
#else
1717
using System.Text.Encodings.Web;
1818
using IHtmlString = Microsoft.AspNetCore.Html.IHtmlContent;
@@ -41,25 +41,20 @@ public ActionHtmlString(Action<TextWriter> textWriter)
4141
}
4242

4343
#if LEGACYASPNET
44-
[ThreadStatic]
45-
private static StringWriter _sharedStringWriter;
46-
4744
/// <summary>Returns an HTML-encoded string.</summary>
4845
/// <returns>An HTML-encoded string.</returns>
4946
public string ToHtmlString()
5047
{
51-
var stringWriter = _sharedStringWriter;
52-
if (stringWriter != null)
48+
var pooledWriter = new ReactPooledTextWriter(ReactArrayPool<char>.Instance);
49+
try
5350
{
54-
stringWriter.GetStringBuilder().Clear();
51+
_textWriter(pooledWriter);
52+
return pooledWriter.ToString();
5553
}
56-
else
54+
finally
5755
{
58-
_sharedStringWriter = stringWriter = new StringWriter(new StringBuilder(512));
56+
pooledWriter.Dispose();
5957
}
60-
61-
_textWriter(stringWriter);
62-
return stringWriter.ToString();
6358
}
6459
#else
6560
/// <summary>

src/React.Core/ReactArrayPool.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
namespace React.Core
1111
{
12-
internal class ReactArrayPool<T> : IArrayPool<T>
12+
public class ReactArrayPool<T> : IArrayPool<T>
1313
{
1414
public static ReactArrayPool<T> Instance = new ReactArrayPool<T>();
1515

src/React.Core/ReactComponent.cs

+25-26
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,7 @@ public class ReactComponent : IReactComponent
2727
{
2828
private static readonly ConcurrentDictionary<string, bool> _componentNameValidCache = new ConcurrentDictionary<string, bool>();
2929

30-
[ThreadStatic]
31-
private static StringWriter _sharedStringWriter;
32-
33-
private PagedPooledTextWriter _serializedProps;
30+
private ReactPooledTextWriter _serializedProps;
3431

3532
/// <summary>
3633
/// Regular expression used to validate JavaScript identifiers. Used to ensure component
@@ -49,6 +46,10 @@ public class ReactComponent : IReactComponent
4946
/// </summary>
5047
protected readonly IReactSiteConfiguration _configuration;
5148

49+
/// <summary>
50+
/// Raw props for this component
51+
/// </summary>
52+
protected object _props;
5253

5354
/// <summary>
5455
/// Gets or sets the name of the component
@@ -75,8 +76,6 @@ public class ReactComponent : IReactComponent
7576
/// </summary>
7677
public bool ServerOnly { get; set; }
7778

78-
private object _props;
79-
8079
/// <summary>
8180
/// Gets or sets the props for this component
8281
/// </summary>
@@ -117,9 +116,16 @@ public ReactComponent(IReactEnvironment environment, IReactSiteConfiguration con
117116
/// <returns>HTML</returns>
118117
public string RenderHtml(bool renderContainerOnly = false, bool renderServerOnly = false, Action<Exception, string, string> exceptionHandler = null)
119118
{
120-
var writer = new StringWriter();
121-
RenderHtml(writer, renderContainerOnly, renderServerOnly, exceptionHandler);
122-
return writer.ToString();
119+
var pooledWriter = new ReactPooledTextWriter(ReactArrayPool<char>.Instance);
120+
try
121+
{
122+
RenderHtml(pooledWriter, renderContainerOnly, renderServerOnly, exceptionHandler);
123+
return pooledWriter.ToString();
124+
}
125+
finally
126+
{
127+
pooledWriter.Dispose();
128+
}
123129
}
124130

125131
/// <summary>
@@ -146,25 +152,14 @@ public virtual void RenderHtml(TextWriter writer, bool renderContainerOnly = fal
146152
var html = string.Empty;
147153
if (!renderContainerOnly)
148154
{
149-
var stringWriter = _sharedStringWriter;
150-
if (stringWriter != null)
151-
{
152-
stringWriter.GetStringBuilder().Clear();
153-
}
154-
else
155-
{
156-
_sharedStringWriter =
157-
stringWriter =
158-
new StringWriter(new StringBuilder(512));
159-
}
160-
155+
var pooledWriter = new ReactPooledTextWriter(ReactArrayPool<char>.Instance);
161156
try
162157
{
163-
stringWriter.Write(renderServerOnly ? "ReactDOMServer.renderToStaticMarkup(" : "ReactDOMServer.renderToString(");
164-
WriteComponentInitialiser(stringWriter);
165-
stringWriter.Write(')');
158+
pooledWriter.Write(renderServerOnly ? "ReactDOMServer.renderToStaticMarkup(" : "ReactDOMServer.renderToString(");
159+
WriteComponentInitialiser(pooledWriter);
160+
pooledWriter.Write(')');
166161

167-
html = _environment.Execute<string>(stringWriter.ToString());
162+
html = _environment.Execute<string>(pooledWriter.ToString());
168163

169164
if (renderServerOnly)
170165
{
@@ -181,6 +176,10 @@ public virtual void RenderHtml(TextWriter writer, bool renderContainerOnly = fal
181176

182177
exceptionHandler(ex, ComponentName, ContainerId);
183178
}
179+
finally
180+
{
181+
pooledWriter.Dispose();
182+
}
184183
}
185184

186185
writer.Write('<');
@@ -270,7 +269,7 @@ protected void WriteSerializedProps(TextWriter writer)
270269
{
271270
var pool = ReactArrayPool<char>.Instance;
272271

273-
_serializedProps = new PagedPooledTextWriter(pool);
272+
_serializedProps = new ReactPooledTextWriter(pool);
274273

275274
using (var jsonWriter = new JsonTextWriter(_serializedProps))
276275
{

src/React.Core/ReactEnvironment.cs

+11-3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
using System.Threading;
1717
using JavaScriptEngineSwitcher.Core;
1818
using JSPool;
19+
using React.Core;
1920
using React.Exceptions;
2021
using React.TinyIoC;
2122

@@ -329,9 +330,16 @@ public virtual IReactComponent CreateComponent(IReactComponent component, bool c
329330
/// <returns>JavaScript for all components</returns>
330331
public string GetInitJavaScript(bool clientOnly = false)
331332
{
332-
var writer = new StringWriter();
333-
GetInitJavaScript(writer, clientOnly);
334-
return writer.ToString();
333+
var pooledWriter = new ReactPooledTextWriter(ReactArrayPool<char>.Instance);
334+
try
335+
{
336+
GetInitJavaScript(pooledWriter, clientOnly);
337+
return pooledWriter.ToString();
338+
}
339+
finally
340+
{
341+
pooledWriter.Dispose();
342+
}
335343
}
336344

337345
/// <summary>

src/React.Core/PagedPooledTextWriter.cs renamed to src/React.Core/ReactPooledTextWriter.cs

+39-9
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@
66

77
namespace React.Core
88
{
9-
internal class PagedPooledTextWriter : TextWriter
9+
public class ReactPooledTextWriter : TextWriter
1010
{
1111
private readonly IArrayPool<char> _pool;
1212

13-
public PagedPooledTextWriter(IArrayPool<char> pool)
13+
public ReactPooledTextWriter(IArrayPool<char> pool)
1414
{
1515
_pool = pool;
1616
}
1717

18-
public const int PageSize = 1024;
18+
private const int PageSize = 1024;
1919

2020
private int _charIndex;
2121

@@ -69,11 +69,7 @@ public void WriteTo(TextWriter writer)
6969
{
7070
var page = pages[i];
7171
var pageLength = Math.Min(length, page.Length);
72-
if (pageLength != 0)
73-
{
74-
writer.Write(page, index: 0, count: pageLength);
75-
}
76-
72+
writer.Write(page, index: 0, count: pageLength);
7773
length -= pageLength;
7874
}
7975
}
@@ -96,6 +92,40 @@ public override void Write(char[] buffer)
9692
Write(buffer, 0, buffer.Length);
9793
}
9894

95+
public override string ToString()
96+
{
97+
var length = Length;
98+
99+
if (length == 0)
100+
{
101+
return string.Empty;
102+
}
103+
104+
char[] sb = _pool.Rent(length);
105+
106+
int index = 0;
107+
108+
try
109+
{
110+
for (var i = 0; i < pages.Count; i++)
111+
{
112+
var page = pages[i];
113+
var pageLength = Math.Min(length, page.Length);
114+
115+
Array.Copy(page, 0, sb, index, pageLength);
116+
117+
length -= pageLength;
118+
index += pageLength;
119+
}
120+
121+
return new string(sb, 0, index);
122+
}
123+
finally
124+
{
125+
_pool.Return(sb);
126+
}
127+
}
128+
99129
public override void Write(char[] buffer, int index, int count)
100130
{
101131
if (buffer == null)
@@ -153,7 +183,7 @@ public override void Write(string value)
153183
count -= copyLength;
154184
}
155185
}
156-
186+
157187

158188
protected override void Dispose(bool disposing)
159189
{

0 commit comments

Comments
 (0)