YTread Logo
YTread Logo

Jesse Kipp - Reconciliation: The Root of Performant Applications | React Next 2019

Apr 09, 2024
Hi, I'm Jesse, I'm an engineer at CloudFlare and you know a lot of you here may know CloudFlare as a CDN or DDoS protection and all that stuff, actually the CloudFlare dashboard is also built into React, so we use React a lot internally. For that, when you log in and change your DNS records or whatever, you're using a

react

app, so I'm going to start my talk by introducing for those of you who aren't familiar with it, Conway's Game of Life, that's how it was made up. in 1970 by a mathematician called John Conway and it is sometimes described as a zero player game, so you start with a square of a grid of cells and each cell can have an initial state where it is alive or dead and then there is a turn sequence. and in each turn a cell can die or come back to life depending on the state of the cells surrounding it, so the algorithm is really simple, if a square is alive and has two or three neighbors that are also alive, it stays alive ; otherwise it dies if The cell is dead and has exactly three neighbors, it comes to life, otherwise it stays dead, so I wanted to write the worst possible application, something that would work terribly, so I came up with this idea.
jesse kipp   reconciliation the root of performant applications react next 2019
I'm going to try to implement a Conway Game. Life in

react

I will have a hundred percent grid, each grid cell will be a Dom node, so it will be 10,000 dominoes and I will update each Dom node every time the timer advances and the game of life evolves and I just go I tried to make this terrible app and I kind of failed, so let's see why. First of all, you know I tried to break all the rules. You know, look at the performance recommendations. It's right for Peru and it has all these things you're supposed to do.
jesse kipp   reconciliation the root of performant applications react next 2019

More Interesting Facts About,

jesse kipp reconciliation the root of performant applications react next 2019...

A long list of elements should have keys, don't pass extraneous properties of your element to your components and you know you might not create a huge list of 10,000 elements in total. within a single render call, so I did all that and learned a few things along the way about this, first of all, react is pretty fast, especially if you're using pure react with no other libraries or systems on top of it all. The application I wrote is about 100,250 lines long, so for reasons that I hope will be clear to all of you by the end of this talk, this was actually a terrible application for trying to demonstrate poor performance on uniform fields of low elements. deep ones that are incredibly fast. render and it's actually hard to make them slow and there were a couple of things that mattered a lot more than any code I wrote about how to make things fast.
jesse kipp   reconciliation the root of performant applications react next 2019
First of all, using a production build instead of a react development build and that. it was worth about four times the performance, 4 times the performance improvement and then the other thing was that the debugger makes a big difference in the performance of your website so I would be working on the website and I would try to make it slow and so I do . optimization and it would speed up and then try again, reload and do an optimization and it would slow down, close the debugger and I definitely don't have any breakpoints set even if they are disabled.
jesse kipp   reconciliation the root of performant applications react next 2019
I can't do performance testing that way so I instrumented my app with a small timer, it starts in the render loop and records the time and then has a callback set with time 0 so that it comes back into control as soon as The rendering stops, so Measure the time, so my little app took about 160 milliseconds to render each iteration of 10,000 dominoes, not too bad, not too good. I guess depending on your perspective of what was trying to be achieved here, you definitely wouldn't want a one hundred and sixty-three millisecond render cycle in your application, although the right people write faster than that, but in the end almost all the performance or the lack thereof came down to a D optimization, which we will return to towards the end of the talk.
Come on, let's do a reminder about react without JSX, so how many people have written a react component call? Reaction doctrine element call at any time from the first day they learned to react. I see like a handful of L hands, some more than me. expecting JSX to actually be the compile time syntax for the react build component, there is a babbling component that goes through your code and looks for all the JSX and turns each JSX element into a react build component call with the component and the children that are going to be called, so let's open up our command line and type, type thread, create rat react app and we take a nap that looks like this because I removed a couple of things to make it even shorter, like this is what our application looks like in JSX, so now we take our heads and run babel in our heads eep-eep eep-eep eep-eep eep-eep eep-eep and implement the same thing as creating calls to elements, so there is a couple of things to note here about this, the callback, the return value of create element is an object called element and the react documentation describes it as cheap and to create this, like all other functions, it is executed from the inside out, so the element creation code is executed first and then passed. to create element P and so on down the chain from the bottom, essentially the bottom of the tree to the top and what we're passing in our props and children components, and at the end once this call is evaluated , we have a tree of objects. where we have a

root

and then there are object references to each of its children and so on, so you'll probably recognize this, what else is a directed acyclic graph?
Dom, this is a common way to represent egg laying. in computing in general and especially in the web world, so the example we just saw was react create component called with only HTML elements, but what about our own components? Wow, that should say create element there, okay, so you have to notice it here big. eros is that there are no parentheses right, our babble has compiled it or we have written this and we have placed UH Nexen or component and react takes care of managing the lifecycle for us, so after calling this if necessary react to instantiate the bitter object or call our stateless functional component and cache the result and make it so that we don't have a complete image of the Dom until it recursively descends all the components that are in the tree and does this for everything in the tree, this is how react manages all our lifecycle

applications

that it will also call, there is a constructor, there is a component that we will mount, there is a component that needs to be updated, there is rendering, so react has a cached instance of our component class that you can call all of them. those life cycles work as the rendering process takes place, so

reconciliation

is the process by which the tree of elements we have built becomes the Dom that is presented to the user, so the problem you are solving is called graph edit distance and it is a You know that the generic graph edit distance algorithm is an N-bucket algorithm which, for any reasonably sized component tree, would be too slow to run on the browser, so react performs a series of shortcuts that make it a single pass through the tree. linear in the number of nodes that are in the tree and a lot of the best practices that emerge and are described for building react components come from the way

reconciliation

is done, so let's say a render call has generated an elemental and it has a change in the Dom node, so now the reconciliation will take place, so we have our elemental, we have our world react state cache and then we have our actual Dom browser, which are the elements that are presented to the user react and start looking at the two things in the left div.
Okay, we're making a good headline. Okay, so look at each element from the

root

of the tree down and then look recursively. each child and determines if that child needs to be replaced, so image image okay, we're doing great, so P div oh well, we have a change in Dom here, so we're going to need to make a change, so react does a change to its internal state and then it starts building an edit list of things that will be changed in the Dom, so when we run this in the dom, we will remove div and add e.g.
We will continue down the tree. We're going to add an edit and then we'll add the rest of these things as well, so we have our element tree, we have our internal representation and we have our dom and an edit list and the final step, the reactors will commit. all these changes and running all these edits against the dom, at which point the browser paints, the rendering is complete, the element tree is discarded and the dom now represents what our render call proposed to show to the user, so What made Happy Squares a slow app? You look at this process no matter what happens in the rendering process, if you end up with a tree of elements that looks like the things that are in the dom, there is very little work to do in this middle part where you are going through reiax rendering . so no matter how you tried to manipulate the render calls, what came out of the render was an elementary element that always looked exactly the same as what was there, it was ten thousand little squares, some of which were on and some of which were off, like this I mentioned that I did a D optimization to really mess up the whole app and that was I wrapped everything in this circuit breaker component, so what it does is it takes a value and depending on whether that value is true, it puts the children inside a div and if the value is false II, it puts it inside P and if we look at what happens in our representation as in our reconciliation as it goes down, it says oh, there used to be a div here, now neppy and I changed the value of Props they don't value every cycle of the game of life and so every time it went down, it would discard its internal representation of the 10,000 nodes, redraw them, and then create an edit list that traversed all those nodes outside the dom and the recreated so that There is a fast version and a slow version of Happy Squares.
The quick version does not have the switch and has a couple more optimizations that turned out to make a difference, a very small difference compared to this one and this is not far off at all. Presented in this form, of course, it's ridiculous, but you know, with the best of intentions, it's quite possible that sometimes nodes will be inserted into the dom that potentially react confusingly about how it's needed, what continues to exist and what doesn't. in a case. This way, some well-meaning developer might create a small component and need something to attach a modal to or attach some other element that has positioning value, so when creating a component, something happens and we change the shell around its elements secondary. well, unfortunately, that makes all the children re-represented like this and then another possibility is that it's not such a terrible thing, but the reaction could be confused about children living under one element, let's say under this P we have three children and if we insert a child at the beginning of the list it could potentially react and start discarding other nodes below that P that we want us to keep because they have very large and large render trees, so here's our optome, here's my optimized version of the game of life. so you can see that it takes about 24 30 milliseconds to render through it and that's correct, creating 10,000 elements, but I put a counter inside the render method of the class that represents each cell inside the game of life and we see that only those nodes that are actually changed become optimal.
One of the optimizations that made the difference here was implementing the component, it should be updated, and just by looking at the props, we only have one thing we care about for this element, which is whether the cell is live or dead. So after having done this experiment, if I wanted to try to make an even worse app, one that ran even slower, I would take a different tack. I wouldn't try to build a component that had such a shallow tree. I build deeper trees and a situation where you could react by spending a lot of time optimizing the Dom reconciling the Dom, let's say you had a bunch of squares on the screen, a bunch of different squares on the screen and they had different things on them and some of they had memes with cats and some of them had like your friends posted pictures of their kids and some of those square your friends without kids posted pictures of food and then some acquaintances have posted conspiracy theories if you can imagine a website like that there There are many different elementsthat move around the page and the reaction can get confused about where each element should live unless you follow some of the recommendations, such as using keys to indicate which elements are the same in different rendering passes, so one of the nice things about Conway's Game of Life is that it has incredibly simple rules that can lead to all these different fun things that you can explore and enormous complexity.
About 15 years ago, Stephen Wolfram published a huge book. called a new kind of science where he explored all these ideas about cellular automata and declared them revolutionary and, you know, ever since Conway's Game of Life was created, people have implemented entire Turing machines into the game of life. life and has created abstractions. which allow you to do calculations with this as a calculation system, but it's also fun to explore and play around a bit. I'll post the link of this app on github later so you can play with it if you want. I guess as a final thought, one of my early mentors in software development once told me to never call a library function that you can't write yourself and I added an asterisk here on the right this has always been a bit more aspirational for me How practical and as computer programmers the first thing we have to decide is whether this statement is recursive I want to write a paper write some JavaScript Do I need to know how a JavaScript interpreter works?
It works if I need to know how a JavaScript interpreter works. Do I need to know how memory allocation works? Yes I need to know how memory allocation works. Do I need to know how the computer's virtual memory subsystem works? So I'm down and down and down so it's probably not recursive and then secondly, you know, the second warning makes this more of a guide than a rule, there are some areas that are quite complicated and I'm not sure be able to implement them sometime. I'm not sure I can build a fully standards-compliant CSS version 3 rendering engine which I find quite complicated, but I still use it and it's a useful idea from Monnet that I should consider and discuss.
Please tell me where to explore and how to explore software development as I progress in my career, so thank you all, Happy Squares is on github if you feel like playing with it or trying to make it slower or faster or play with the game. of life or something like that, thanks

If you have any copyright issue, please Contact