Home

Awesome

react-dom-stream-example

This is a simple example Express app for react-dom-stream.

How to run it

You must have node & npm installed to start.

git clone https://github.com/aickin/react-dom-stream-example.git
cd react-dom-stream-example
npm install
NODE_ENV=production PORT=5000 npm start

Obviously, you can choose a port other than 5000 if you'd like.

The site has a very simple page that reads out a recursive tree of simple divs, using either ReactDOM.renderToString or ReactDOMStream.renderToString. You can access it at:

http://localhost:{PORT}/{renderMethod}?depth={d}&breadth={b}

There is also a simple JavaScript test script that launches curl, called test.js, that will run against both /string and /stream at a number of depths and report the number of bytes, TTFB, and TTLB for each. It takes the following arguments:

Some simple preliminary results

I ran some simple tests on my MacBook Pro (Retina, mid-2014, 2.8GHz) and came up with these results running 1,000 iterations (all times in ms):

DepthBytesStream TTFBStream TTLBString TTFBString TTLBTTFB DiffTTLB Diff
16290.70.80.70.72.8%4.6%
28280.50.60.40.429.4%31%
312480.80.90.60.643.6%40.9%
421380.910.60.746.6%41.6%
540121.21.20.9128.2%26.2%
679511.81.81.41.522.3%21.9%
7162152.82.92.32.421.5%21%
8335204.44.63.9410.4%13.7%
96967948.27.37.5-45.2%10%
101450503.815.514.114.3-73.1%8.1%
113018433.730.728.328.5-86.9%7.6%
126275364.27056.857.2-92.6%22.4%
1313039504.9146.2117.2117.9-95.8%24%

(I removed some of the columns that show how many bytes are returned from the server for ease of reading.)

With the smaller pages (33K and smaller), react-dom-stream is a net negative; it adds time to both TTFB and TTLB. Note, though, that the absolute amout of time added is pretty small, usually less than a millisecond.

With the larger pages, TTFB stays more or less constant as the page size increases, and the TTLB increases between about 10 to 20 percent.

I also ran a less scientific, real world test of 100 iterations on a dyno on heroku, to see what happens when real world latencies are added:

DepthBytesStream TTFBStream TTLBString TTFBString TTLBTTFB DiffTTLB Diff
163099.8100.5104.7105-4.7%-4.3%
282798.199102.4102.6-4.2%-3.5%
3125097.598106.4106.6-8.3%-8%
42138100.7101.4101.7107.4-1%-5.6%
5400999.7107.4103.3104.3-3.5%2.9%
67952103.1104.3103.5104.9-0.4%-0.6%
716220109.4206112.2202.8-2.5%1.6%
833510111.5281.6113.5282.8-1.7%-0.4%
969698111.2398.5122.8434-9.4%-8.2%
10144839112.3805.1139.6838.5-19.6%-4%
11301716113.61238.11761165-35.4%6.3%
12628208110.31652.62461790.3-55.2%-7.7%
131305113112.42828.2525.33047.6-78.6%-7.2%

In this test, react-dom-stream does better than React almost across the board. In the smaller pages, the differences between react-dom-stream and React are negligible, but as the page gets larger, the difference in TTFB grows.

In constrast to the zero-latency, infinite bandwidth tests against localhost above, though, TTLB does pretty well in the real world tests, with react-dom-stream generally beating React by a small amount (about 5%). My current working theory is that this is at least partly a function of the responses being bandwidth-constrained, and react-dom-stream gets a head start in filling up the pipe.

There's clearly a lot more to be done here; this is a microbenchmark of a complicated topic. However, it's worth noting that the gap between streaming and string rendering should in theory get larger as pages get larger, as connection latency increases, and as bandwidth decreases.