Speedy Apps with Angular and React by Dave Smith at ng-conf 2016.
DAVE SMITH: Hey, everybody.
Well, today I wanted to talk– oh, I really
should have turned this off.
Oh, I’ve got to take this.
Thanks for calling back.
So I just wanted to call and tell you,
remember how last year I called you,
and I was all happy because I didn’t
have to use jQuery anymore?
Because this Angular thing has been so awesome?
Well, now I get to use React in my Angular.
I thought maybe you’d like to know about that.
(WHISPERING) I love you too.
[LAUGHTER AND APPLAUSE]
So I usually like to start off with a joke.
I was going to tell a really hilarious one,
but I didn’t really know how you would react.
Before we talk about performance,
it’s important for us talk about what is our job as engineers.
Engineering, I believe, is when that
which is theoretically possible through science
reaches a compromise with that which is economically feasible.
And this is where we find ourselves constantly
tugging between the trade-offs of what’s possible
and what we can afford to do.
Performance is really hard.
It’s a hard problem.
In fact, this was a quote that I recently
found– I don’t think you’re measuring what
you think you’re measuring.
This is actually Misko to me about this talk.
Here’s a question I get a lot– is React faster than Angular?
Well, the answer is very simple–
that’s a stupid question.
I’m not going to compare apples and oranges today.
Instead, I am going to build a whole new kind of super powered
But first, I feel like I owe you an introduction to React.
Here it is in 30 seconds.
that’s designed to take your application state
and allow you to write code that takes that status input
and returns Virtual DOM, which is really just a set of plain
Reconciling and Rendering Engine,
and then generates from that a set of optimized DOM operations
that need to be performed on browsers to make it real.
A little more detail.
The performance premise of React is
that the DOM is dangerously unperformant for engineers
to work with directly.
So instead, they give you a virtual DOM
to work on, which is an intermediate representation
When your application state changes,
you return new virtual DOM, React
diffs it against the existing virtual DOM
and generates performance-optimized DOM
operations that will then go to the browser.
It can do things like batching reads and writes,
which results in fewer reflows, and it can even
do cool things like generate big blocks of inner HTML
Here’s some links I’d like you to check out later about React.
So now you know a little bit about React–
There’s an obvious conclusion.
Well, the unicorn grumpy cat says that’s really not
So we’re going to just React some of the things today.
But first, I want to tell you a story with two parts.
The first part is tragedy, and the second part is glory.
We’ll start with the tragedy.
This is a piece of UI that we developed at my company
It’s written with Angular.
Our product managers came to us, as product managers are
wont to do, and they said, please
add a new column to this table.
And I thought, oh boy.
We already have an NG repeat table,
and now you want us to do an NG repeat list
inside of our NG repeat table.
So I did a little bit of advanced performance
mathematics, and I came up with the following.
If I have a slow NG repeat table and I add to it a nested NG
repeat, what I get is precisely a really slow NG repeat table.
So I thought, React to the rescue.
Here’s a “wat” moment.
Did you guys know React stole their logo from the Simpsons?
This is the attempt we thought.
Let’s write a directive that internally
uses React to render that list of stuff
so that it can be optimally fast.
We’ll call that directive right inside of our NG repeat markup.
Here’s what happened.
[LAUGHTER AND APPLAUSE]
Here’s why it failed.
React had no ability to batch its DOM operation,
so it couldn’t do the one thing that it’s good at.
And the reason was, it did not control the outer DOM.
And what I mean by that is that Angular controlled the tables
and rows, and then React just had to render inside
of each one of those rows.
So it ended up generating options
like this– append child react, append child react,
append child react instead of just inner HTML.
Also, I should point out, NG repeat, as we learned,
is not inherently slow.
And we ended up implementing this feature with a nested NG
repeat, and it was fine.
Then we go forward to a year into the future.
Just a few months ago– I’m going
to tell you the glory part– product management came
to us again and said, please build the following.
It’s a schedule search algorithm.
It allows users to bring up a calendar,
click a Search button, and then we’ll
start searching in their calendar for availability
Well, this sounded really cool.
But again, I started thinking about performance.
And I was concerned, because we had done apps
like this before where you have a lot of things happening
a lot at a time, which means you’re going
to have a lot of digesting.
What would happen is you’d click Search Week, all of the cells
would go into spinner mode, and then
results would start coming back from the server quickly.
And before we knew it, you’d have a performance challenge
We decided, we already game overed once with React–
should we insert coins to continue, or just
We decided to insert coins.
And this time when we did Angular plus React,
we got a prophetic narwhal.
I’d like to show you what that looks like.
Here we have some code.
Instead of showing the actual app,
I’ve reproduced it in a minimal fashion
so you can just see the relevant bits.
Here we have index.html.
This body consists of just two directives.
One is called My Calendar, and the other
is called My Calendar React.
I’d like to show you what this looks like.
My Calendar and My Calendar React right there,
right now, they’re just a Load button.
When I click this Load button, it
will actually fill in the DOM to represent the calendar.
But before I do that, I want to turn on the profiler.
So I’m just going to hit Start, Load, Stop, just like that.
So now you can see visually what the calendar looks like.
It’s 24 hours tall and 31 days wide for a total of 744 cells.
And here is the profile.
If you haven’t used Chrome’s profiling tool,
I’ll tell you a little bit about it.
The horizontal axis is time.
The vertical axis actually represents
the depth of your deepest function call stack.
For the purposes of this talk, all we really
care about is horizontal width.
The depth isn’t really that important.
I’m going to zoom in here.
You can see the Event Handler that happened here.
And what we can see if we hover here
is down below where it says aggregated total time is
about 544 milliseconds.
That’s across all of these.
Now we’re going to do the same thing in our React directive.
Just click the Load button.
I’m going to start the profiler, click Load, Stop.
Here you can see it did the same thing.
Actually, this one was 87 milliseconds.
And those numbers are a little weird.
When I’ve run this before, it hasn’t
been that slow on the Angular One side,
so I’m going to do this again just
to make sure we get good representation.
So Start, Load, Stop.
Yeah, that’s more like it– somewhere between 300 and 500
So you can see why that happened is because React
was able to generate all of that DOM
by doing a single inner HTML call.
When you give a browser an inner HTML piece of HTML,
it really is the fastest it can run is about that.
Now, the next thing I want to show you
is, what happens when I click this Search button?
So what I’ve got here is a whole bunch of cells.
Each cell is independently searchable.
So I can click on it, and it simulates a trip
to the server that can take up to– let’s
see– I think I said 10 seconds, but let me just double check.
Actually, that’s half a second.
We’ll do it again here.
So each cell can take up to 10 seconds to do a search.
You can see that 4 o’clock hour came back with four results,
and then it just randomly generates a response
with a number in it.
And I can have a bunch in flight at once,
and within the next 10 seconds, they’ll
all return with results randomly generated.
Between 0 and 10 seconds, just like that.
Now, I am using dollar timeout to do this.
So what that means is that every time a search result comes
back, my root scope gets digested, which
means Angular has to dirty check every single scope
And since I have 744 cells inside of a nested NG repeat,
I have 744 scopes at least.
So that’s a lot of dirty checking
that it has to do in Angular One.
So let me just click this button and start the profiler.
So you can see, between 0 and 10 seconds,
each cell is slowly trickling in its results.
That’s enough for now.
Let me expand the profiler.
So what you see here is a thick–
what I like to call sequoia redwood
forest with very thick trees.
There are little gaps between the thick Sequoia trees.
And those little gaps are times when
the browser is responsive to user input
and the event loop isn’t busy.
But the times where you see the colorful areas, the trees, that
is blocking the event loop.
And if you go and zoom way in here,
you won’t be surprised at what you find– 744 scope
digests inside of each one.
Now, this is my fault, because I wrote my app this way
to do dollar timeout.
Dollar timeout is not very performant,
because it assumes that anything could have changed,
so it needs to redigest your whole app.
But let’s go look at the Reactor version.
So I’m going to load it, start the profiler,
hit the Search button.
That’s probably enough.
And let’s zoom in on that.
So you can see here, it’s a different story.
Instead of a forest of thick sequoia redwood trees,
we have a forest of toothpicks, which is what you want to see.
This space between each toothpick
is time when the browser can be fully responsive to user input.
So just to compare a little more carefully here,
let’s just pick about a one-second time chunk there.
So this is from second five to second six on the Angular one.
And then I’ll do the same thing in React.
Here’s a one-second time chunk.
You can see quite a big difference
in the amount of space between each chunk.
So that’s how that looks.
By the way, I could have done some more optimization to make
the Angular One app look more like this, but I didn’t.
Because by default, we’re going to be using dollar timeout,
and this is the kind of thing you’re going to have to debug.
But let me just show you what the code looks like.
So here’s my app file.
The Angular One code, you should be really familiar with.
This is common pattern here.
We have our My Calendar directive.
Inside the My Calendar directive,
I have a nested NG repeat, and then
inside that nested NG repeat, I have a My Calendar cell
directive, which is declared a little bit down here.
And each My Calendar cell has just a couple of NGS
ifs inside of it to decide what state to show
and what should go in there, just like that.
Now, if I scroll down below the calendar cell one,
I’ll show you the directive that has React inside of it.
So My Calendar React was the name
of directive, which you’ll remember from the HTML.
And here’s its link function, which just does one thing.
It says react dot render, and then this weird thing.
Does anybody know what that is?
Has anyone seen that before?
This is called JSX.
It is a way to easily represent HTML right
And this thing is actually a React component,
which I’ll scroll down and show you what it looks like.
So here I have a calendar component.
You declare a React component by saying react.createclass.
Every React component should have a render function.
And the render function returns a bunch of HTML.
Now, it looks pretty templatey, but notice,
This HTML is actually not returning DOM.
This HTML– or this stuff that looks like HTML–
is actually returning virtual DOM.
And this gets compiled by React’s JSX compiler
will execute in the browser.
So you can see here, this is my calendar.
My calendar is just like my angular calendar.
Instead of using NG repeat, we actually use array dot map.
So here I’ve got an array dot map over the hours and an array
dot map over the days.
And inside here, I’ve got a cell component that I’ve written.
And the cell component is another react class
with its own render function that
has a couple of if statements and returns different
HTML depending on the state of the cell.
So that’s actually how easy it is
to integrate a React component into in Angular directive.
Let me show you what happens when we speed things up a bit.
So right now, we saw with a 10-second random timeout
on each cell what it looks like.
If I make that closer to half a second,
you can really start to feel what things look
like from a user’s perspective.
So let’s load up the Angular One, hit Search.
Now, remember, I made it a half-a-second timeout,
so all of these should be done in half a second.
You can see it’s cooking along.
Actually, I think this is not– I think I made them in cache.
That doesn’t look right.
Let’s go to the New Tab.
Maybe that’s right.
It seems awfully slow.
That seems really slow to me, but we’ll just go with it.
Let me show you the React One.
Let me do that again, in case you didn’t see it.
You had to be watching.
So the difference there is not digesting the whole world.
Because in the React app, it was easily– by default,
the design is to only really digest
the things you need to, although it doesn’t have a digest.
And in fact, the root scope digest
didn’t run at all inside the React directive.
So that’s kind of the difference.
So let’s go back to slides here.
There are drawbacks to using React.
First of all, you will add 500 kilobytes of code to your app.
It is not a tiny library.
Secondly, you must have a JSX build step.
You can write Reactive without JSX, but I don’t recommend it.
Thirdly, you now have two frameworks in your app.
Now, this is a problem because you have people to train,
you have developers who won’t know one or the other,
and now they might have to know both.
So it can be a problem.
Lastly, you might very well have to change
We support 14 languages, and we had
to use a very different internationalization
pattern with React than we did with Angular.
React, however, does shine.
In the initial download, it does really well,
because it can batch all of the operations
to generate it really quickly.
And this is mostly thanks to things like inner HTML.
Also, after small state changes, React
is really good about only touching the parts of the DOM
that actually changed.
And it’s even really good when there
is big changes in the DOM, because it can bulk do those,
React is kind of weak after there are no state changes.
If you tell React to re-render your whole app,
it will generate all of the new virtual DOM.
And in my experience, it takes about twice as long
to generate all the virtual DOM for an app of significant size
than it does to run through the digest dirty check once.
For an app I was testing with, for example, you
can get 13 milliseconds verses about 27 milliseconds in React,
which you might think is insignificant,
except 27 is greater than the 60 SPS boundary, which
is 16 milliseconds.
And so it does make a difference.
One of the strategies I use is to not
tell the whole app to re-render, but rather,
find the components that have changed
and tell those to re-render.
So that’s pretty much all I wanted to show you about React,
but I do have one more thing that I wanted to show you.
I did actually build the app in Angular 2.
Thanks a lot to the Angular team for helping
me get this working.
And I just wanted to show you what that looks like.
So first of all, I’m going to hit the Load button.
That’s actually really fast.
Hope you can see that.
Now I’m going to hit the Search button.
So you will want to be watching for this, because remember,
here’s how it looked like with React.
Just pay attention to how long it took.
And here is Angular 2.
[CHEERS AND APPLAUSE]
Angular 2 is really, really fast.
You have to do your own engineering.
You need to measure, observe, and decide for your team.
DAVE SMITH (VOICEOVER): Hey, everybody.
You may have noticed a mistake that I made in my talk
when I was comparing the performance of Angular
2 and the React example.
The problem was that in my Angular 2 example,
the random millis function was written
to return 0 while the react function at the time
was written to return a random number between 0 and 500.
So it’s really not a fair comparison
to show the run times of the two frameworks when one of them
is set up to return more slowly.
I’m really sorry about that.
It was completely accidental.
Now I want to make it right and show you
what it looks like when both frameworks are set up to return
a zero millisecond timeout.
So here is the React example.
And I’m not even going to run the profiler.
I’m just going to let you see it visually.
So I’m going to click the Search All Month button.
And here is the Angular 2 example.
To my eye, the Angular 2 example does look a little bit faster
for this particular example.
But it’s worth mentioning that the Angular team actually
helped me optimize this.
And the React team hasn’t had a chance to look at this at all.
I wouldn’t make any kind of conclusion
about the relative performance of these two frameworks
But I at least wanted to show that I did make a mistake,
and I did make the performance difference look more
significant than it really was.
So I apologize for that.
And thanks for being patient with me as I
work on performance.
Like I said in my talk, performance is hard.
And what I didn’t say in my talk is that I’m a gigantic idiot,
and you probably shouldn’t listen
to anything I say anyway.