top | item 15567657

Netflix: Removing client-side React.js improved performance by 50%

357 points| pjmlp | 8 years ago |twitter.com | reply

163 comments

order
[+] clarle|8 years ago|reply
Hey, I work on the team at Netflix that gave the talk on React in the signup flow in the tweet.

The full talks are available here if people want to watch them:

https://www.youtube.com/watch?v=V8oTJ8OZ5S0&t=11m30s

Thought I'd also provide some more context on some common questions that people have asked.

### Why are you using React to render a landing page?

The Netflix landing page is a lot more dynamic than most people think it is.

It's our most heavily A/B-tested page in the signup flow, with even some machine learning models being used to customize the messaging and imagery that you get depending on location, whether or not you were a previous Netflix member, device type, and a lot more. Even beyond that, Netflix supports almost 200 countries now, and there's a different combination of localization, legal challenges, and value messaging for each one. We end up sharing a lot of the logic and UI for these A/B testing and localization challenges throughout the signup flow, mainly through React components.

The example I always love to give is the <TermsOfUse/> component that we have, which to a Netflix customer signing up is literally one or two checkboxes on the UI, but has some of the most complicated logic in the codebase due to the vast number of countries and user states we support. Because of all this, it's more valuable for us to share these common React components across the entire signup process, both the landing page and the rest of the flow, which is a single-page React and Redux application.

We've seen a lot of conversion value though in improving the performance of the landing page, especially in countries with slower connections, but we don't also want to re-duplicate a lot of the shared UI logic that we have.

The tradeoff that we decided to make is to server-render the landing page using React, but also pre-fetching React / Redux / the code for the rest of the signup flow while on it. This optimizes first load performance, but also optimizes the time to load for the rest of the signup flow, which has a much larger JS bundle size to download since it's a single-page app.

### What's the performance metric that's being used?

It's TTI (Time to Interactive), when the user can fully interact with the page. This is different than TTR (Time to Render) for us, when the user can fully view the page. There's more information in the talk about the differences.

### Why not Service Workers or some other pre-loading / caching mechanism?

We have been experimenting with it, but it's mainly the lack of some browser support - Safari is the main one. Generally the Netflix signup flow needs to have more legacy browser support than the Netflix member experience. Lots of people sign up on a pretty old browser, but only ever watch Netflix on the native mobile apps or a TV device.

#####

Feel free to comment here or tweet at Tony (https://twitter.com/tedwards947) or me (https://twitter.com/clarler) if there's any other questions that we can help answer.

Though from a lot of experience, 140 characters isn't always enough to provide enough context for JavaScript framework discussions. ;)

If these sort of performance and UI challenges seem interesting to you, our team is also hiring for UI engineers and an engineering manager!

* Senior Software Engineer (React, Node): https://jobs.netflix.com/jobs/864767

* Senior Software Engineer (Android): https://jobs.netflix.com/jobs/864766

* Engineering Manager: https://jobs.netflix.com/jobs/865119

Cheers!

[+] spicyj|8 years ago|reply
I work on React. We’d love to hear from your team sometimes and collaborate on this sort of thing. We’re solving many of the same problems but I rarely hear from Netflix engineers except at talks when announcing they’re avoiding React or have forked it, often for reasons we weren’t even aware of.
[+] pluma|8 years ago|reply
So in other words: the main reason removing the React code in the frontend in this case gave such an immense performance benefit is that the logic used to compute the rendered UI is significantly more complex than the logic necessary to make that UI interactive.

It's not React that's slow, it's the logic needed to render the page?

[+] samsaccone|8 years ago|reply
Hi could you post some before and after traces (chrome dev tools recordings) of the site. Performance is nuanced, and the original tweet only helps to put down others (the react team) unfairly.

I think the win here is less about react and more about not running as much javascript on the client. I hypothesize that the traces will show this, but it is impossible to know for sure without them :)

Thanks in advance!

[+] aith|8 years ago|reply
In the talk you say that you reduced JS and therefore lowered TTI and saw more clicks on the signup button. Is it possible that you are just _tracking_ more clicks, but the total is the same?

Does it really matter how much JS there is if it's loaded after HTML and the user can already move to the sign up step without it?

[+] Flow|8 years ago|reply
Please make the search textbox always visible. Most of the times I go to Netflix.com is to see if it has the movie I want to see. (I live in Sweden, Netflix is pretty small here)

And going to the front page of Netflix, clicking the Search icon is not a pretty experience. What happens next is a chuggy chuggy animation of the textbox gliding out, and typing in it is a disaster of input lag.

I bet you fire an event for each key I press while in there? Perhaps wait with that until the rest of the page has loaded?

[+] drdiablo|8 years ago|reply
Thanks for taking the time to answer everyone's questions!

Do you simply use Nodejs to do the SSR? I've seen some complaints about the difficulty of scaling node to run well in a cluster, and about security things. Have you had to deal with that?

I'd honestly love to see what you did there. People use Java for the reason that all of those questions have decent answers by now.

[+] devrandomguy|8 years ago|reply
I've been ranting here occasionally about the infuriating unprofessionalism of a web app that can't operate without JS. There is very little that you can do with JS that can't also be done with the help of a server, unless you start making up overly-specific requirements about what technologies are used, or writing user stories for robots. As a diehard NoJS guy and a developer who uses React professionally, my community's willingness to accept of the problem, and obliviousness to the solutions established by the React devs themselves, are pretty embarrassing. And it's not like I hate the language, Node has been my go-to application server for years now (Clojure is displacing that for me, but I digress).

Last year, I was building a simple SVG based chart dashboard for internal usage. Being a NoJS guy, I would sometimes disable JS while developing, on purpose or otherwise, and aside from forcing me to manually hit refresh in the browser, things generally worked. I added a couple links (styled as buttons) for zooming, to supplement the JS based drag-window zoom, and let the browser scroll the potentially very wide SVG chart within a div. If necessary, I could have even embedded the whole thing in an iframe, to avoid triggering whole page reloads, but our caching story was tight enough to compensate. Also, the React-rendered SVG represented the bulk of the markup on the page anyway.

Interactive visualisation, no JS needed. It added maybe an extra 10% to my workload (we already had the SSR stack), and helped me to avoid a variety of little glitches that plague many client-only apps, glitches that users learn to tolerate with mild disgust. The satisfaction of seeing our in-house dashboard pop up "instantly" with data, while Parsely and New Relic were still churning spinners or stuttering while waiting on JS, or even waiting for initial data after waiting on JS, was very cathartic. TTI can equal TTR, we have the technology, we've had it for a decade or so.

[+] solidr53|8 years ago|reply
Split code by routes? Split interactions and the view layer? fiber? Stream the render?
[+] zaf|8 years ago|reply
It is quite telling that you give the example of the <TermsOfUse/> component which has "one or two checkboxes on the UI" that "has some of the most complicated logic in the codebase".
[+] christophilus|8 years ago|reply
I was at the All Things Open conference this week, and Yehuda Katz gave a talk on Glimmerjs[0].

It was enlightening. The size of your front-end application is generally dominated by view code. So, they precompile views into a super simple set of binary VM instructions (making your views very compact). These views don't go through the JS compile / parse phase on the client (saving hundreds of ms, up to seconds on slow devices). They are instantly executable by a small VM written as a JS library, and can be streamed in and rendered as they arrive (the way plain ol' HTML pages do). Turns out to be hella fast, but still gives the benefit of rich client-side rendering capabilities.

[0] https://glimmerjs.com/

[+] tomdale|8 years ago|reply
For folks who want to play around with this, we've got an interactive playground at https://try.glimmerjs.com/ that lets you add components, templates and helper functions.

In a nod to The Net, you can click the π symbol in the bottom right corner where you'll get a debug view of the disassembled binary bytecode.

[+] bm1362|8 years ago|reply
That's pretty exciting. I'm curious when we can just compile our views into some IR or byte code that can be natively run. Isn't that kinda what WASM is trying to do?
[+] CyberDildonics|8 years ago|reply
Why use binary VM instructions with a VM written in JS instead of just straight binary data? Why does it even need to be instructions in the first place?
[+] graphememes|8 years ago|reply
Anyone thinking on betting on Ember, or Glimmer.

Word of advice / wisdom from having built multiple platforms / sites with it:

Don't.

[+] throwaway2016a|8 years ago|reply
Sounds like form the comments they still use React they just defer loading it until after the page is otherwise usable.

I think this is a fairly common use case for server-side rendering in React and I wonder how much of this improvement they would have seen just by SSRing the page and putting the React scripts at the end instead of the header (or using defer). This is the strategy I use with any React marketing type pages.

Edit:

Just to give more detail incase anyone is wondering, usually marketing pages are relatively the same for every user (unless you are doing identity based personalization or a/b testing) so often you can get away with pre-rendering all the HTML generated by the React. Then you don't even need to load React server side, you just serve up a static file.

[+] devrandomguy|8 years ago|reply
Yep, and personalization and A/B testing can be accommodated with query params. By whitelisting those AB params in the caching layers, you can mostly prevent a performance difference between A and B, something that may have messed up our results with a 3rd party AB testing service.
[+] Raphmedia|8 years ago|reply
Well, of course it will. You are trading loading an entire application for loading a static page.

I'm always amazed at those devs who load entire applications framework when their end goal is to have a slider at the top of a page.

[+] dustingetz|8 years ago|reply
If you get your SSR right, you can just not serve javascript for landing pages and readonly dashboard type things. This is what Hyperfiddle does - all readonly things work 100% with javascript disabled (try disabling it in the dev tools)

http://hyperfiddle.net

[+] mosselman|8 years ago|reply
I like how the people in replies to the top tweet seem to get angry at someone implying that React is not great.
[+] detaro|8 years ago|reply
For me they mostly show people asking for numbers and people making fun of them for using React for a boring landing page.
[+] FLGMwt|8 years ago|reply
From the slides, it looks like the performance metric in question was TTI (Time to Interactive).
[+] positivecomment|8 years ago|reply
Today we learned: Removing an advanced library from a simple project increases performance.

Sorry for being sarcastic but don't you also find this too obvious?

[+] danvasquez29|8 years ago|reply
I think it's the 50% part that we're meant to pay attention to. For me that's a pretty drastic, "why would you ever put this on the client side now that you know this" kind of thing.
[+] grandalf|8 years ago|reply
You are correct. This is such an obvious, simple thing that anyone with a small bit of experience optimizing a static website for render completion would understand.

React is designed to allow a server-side render and an async load of the js library to allow it to be used in this kind of scenario without impacting perceived load time or "time to interaction".

[+] CyberDildonics|8 years ago|reply
> Sorry for being sarcastic but don't you also find this too obvious?

If we pay attention to how bloated most web pages are, it seems it is not obvious at all.

[+] afshinmeh|8 years ago|reply
I was thinking about the same thing. Well, you can remove CSS as well, I bet it would improve the performance.
[+] jordache|8 years ago|reply
Netflix website is a simple project!? Wha?
[+] jasonlotito|8 years ago|reply
What's funny is that your conclusion is incorrect.
[+] narag|8 years ago|reply
Today we learned: Removing an advanced library from a simple project increases performance.

The library that slow down the UX terribly is "advanced" while the project that is being the victim is "simple".

[+] drinchev|8 years ago|reply
> ...improvement on our landing page

React on a landing page sounds like an overkill to begin with.

[+] thosakwe|8 years ago|reply
This is what we need for LinkedIn. I am yet to see a slower site.
[+] retrac98|8 years ago|reply
Yup, the Twitter replies are pretty much what I expected. This tit-for-tat JS pissing contest is so old. Just use what makes sense for your project, there are no silver bullets.
[+] techaddict009|8 years ago|reply
We learned this hard way :P

We avoid fancy tools as much as possible and use basics as much as possible.

Laravel + Bootstrap + JQuery + MySQL works pretty well then this modern stuff.

Easy to implement, deploy and manage.

P.S. Use knife which you really need. Try to use simple knife as much as possible.

[+] maxhallinan|8 years ago|reply
> Laravel + Bootstrap + JQuery + MySQL works pretty well then this modern stuff.

It's interesting to remember that Facebook started out as a PHP application. I imagine that Facebook's original tech stack closely resembled the stack you're recommending. And scaling that stack is what led to the creation of React. If you choose to build a rich user interface (like Facebook or Netflix) on top of that stack, you will likely find yourself creating abstractions to manage the complexity. Those abstractions will be equivalent in their utility to React, Ember, Angular, etc.

I agree that a website does not always need or benefit from a React or an Ember. Small dynamic behaviors behaviors can be implemented with less powerful tools. But, the power of your abstractions will need to scale with the complexity of your UI behavior. That's why, at a certain point, the abstractions provided by React _are_ the right choice and jQuery is not.

Regardless, the slide featured in this tweet does not comment on React working or not working well. As they say in a reply to that tweet, the application still loads React and renders React components. What they are presenting is an interesting optimization that has to do with the unique performance constraints of Netflix's UI.

[+] floatboth|8 years ago|reply
What do you use jQuery for in 2017? querySelector, classList, fetch, … — everything we used jQuery for in 2010 is built-in.
[+] jordache|8 years ago|reply
"resulted in a 50% performance improvement on our landing page"

What constitutes their landing page? The un-authenticated page or the authenticated page? If the latter, is the page with all the title art cards?

[+] polskibus|8 years ago|reply
Was performance measured against fiber or the old rendering engine?
[+] sandGorgon|8 years ago|reply
How are they doing this ? This sounds surprisingly similar to Gatsbyjs ...Except it's real-time .

Anybody know how drop-in this is for existing react code ?

[+] baxtr|8 years ago|reply
Wow, this is crazy. As a huge vue.js fan I'd argue that the percentage value would be much lower with vue. But, I’m not totally sure.
[+] ukulele|8 years ago|reply
I'm also a big fan of Vue, but why would it be different in this instance?
[+] programminggeek|8 years ago|reply
The irony is that React was supposed to make everything faster...
[+] solidr53|8 years ago|reply
Actually you are incorrect, not everything, but the most important part, development time.
[+] thrownaway954|8 years ago|reply
did the same thing by removing ckeditor from a page it wasn't being used on. we all go through this at one point when taking another look at something with fresh eyes.