benmvp / ama

Ask me anything!
https://github.com/benmvp/ama/issues?q=is%3Aissue+is%3Aclosed
3 stars 3 forks source link

How can I maximize react's performance when leaf nodes are changing rapidly but not the DOM structure above them? #8

Closed Costigan closed 7 years ago

Costigan commented 7 years ago

Ben, I was at the Modern Web meetup Tuesday evening and also thought your talk was excellent. I'm a react beginner and, while I've read about most of the tools and libraries you mentioned, I have experience with almost none of them. Advice from an experienced developer about where to invest precious learning time is very helpful. Thank you.

I have a question about react that I'd hoped to find someone to answer at the meetup, but at the end of the evening, I forgot and left. Since you have this AMA, I thought I'd try to make up for that.

The general form of my question is this: Is react a good choice for my application, or is there a better choice? More specifically, it's a question about how to achieve the best repaint performance when rapidly changing text DOM elements. The stressing case for my app involves updating a large number of leaf DOM elements (several thousand) at ~10 hz. This is exactly not the case where you can mark large subtrees of the DOM that do not need to change with shouldComponentUpdate().

Still more detail: I'm a server-side developer on an open source SPA at work (https://github.com/nasa/openmct). I know very little about the client side. The client was written originally in Angular 1 and most of the existing views remain that way, but the client team is moving toward an approach that allows new views to be written in other frameworks or libraries.

The goal of the application is to provide displays for a mission control center, starting from the thesis that web 2.0 technologies are mature and performant enough to do that. Building on web technologies would simplify deployment and open up ways for people to be connected to the data using tablets and phones while moving around the control center.

Our current displays typically use X windows and have a late 90s feel. At their root, most of our displays are just like a metrics dashboard or a dashboard for IoT data. A typical spacecraft has 40-80k individual measurements, each of which produces a new value at some frequency. The primary task is to display this telemetry in real-time as very large tables of latest values and as stripcharts. Displays tend to be very high density because that allows flight controllers to access more information more quickly than an interface that required drilling down would. This works because they get a lot of training and time to get familiar with the displays.

In addition to streams of individual measurements, there are many kinds of objects that get assembled from spacecraft data, like like vectors, quaternions, images, spectra, software configuration tables, and on and on. On top of that, there are many more kinds of objects generated on the ground and exchanged within the flight team. Each data type has one or more useful ways to render it (views). Frameworks, like React, that make it easy to build components, fit this need very well. But a framework has to handle the high density displays at a minimum.

So, back the my question. What's the best way in react to achieve high repaint performance when it's the leaf nodes that are changing at a high rate but the structure above them changes much less frequently (when the user switches pages or opens a new view of an object).

I've tried some simple experiments like a table with ~1000 elements, and just letting react do its thing has yielded surprisingly good performance. But I haven't realistically modeled the depth of the component hierarchy were I to use react fully.

The leaf nodes represent the current value of some measurement. That value gets converted to a string and written to the DOM. For this application, in virtually all cases, these strings can be fixed size such that, when the values change, no layout / reflow needs to happen. Just a repaint. My central confusion is that I don't know how to tell react that.

So, I think my choices are:

  1. Let react do its thing and live with the cost of the virtual DOM diffing
  2. Let react lay out the DOM, retrieve references to the leaf DOM nodes and jam in new strings without telling react about the changes
  3. Used fixed positions for everything so reflows don't propagate far. But I won't get the (huge) benefit of the browser's layout algorithm.

Am I confused? Is there a better choice than these? Thanks, Mark Shirley

benmvp commented 7 years ago

Hey Mark!

Thanks for reaching out. I'm glad you enjoyed the talk! I'm also glad you didn't ask me this question after the talk because I would've been so overwhelmed and too mentally fatigued to give you an adequate answer.

In general, with these types of big architectures, I design with performance in mind, but still build first. Probably the worst thing you can do is build something super performance, but doesn't actually work or is buggy.

So I say, first see how things perform with letting React do its thing. Maybe the reconciliation (i.e. "virtual dom diffing") overhead will be too much, but at least the app works. You can test out the user experience, get feedback about the design, etc. etc.

If the performance is just too bad then I can think of two courses of action to improve performance: reduce the number of updates (easier) or further optimize the existing updates (harder). It may be that the flood of data you're giving it is too much for someone to parse, so dropping updates may be imperceptible. If not, then you have to proceed to option 2 or option 3.

I'm not sure how much option 2 will by you honestly. Cuz you'll have to manually maintain the references and associations with data. And then write the update code yourself. My sense is that your manual code will take as long as React's reconciliation algorithm.

Option 3 will definitely help w/ the repaint issue, but man will that be a pain to maintain. I'm not sure if the cost of basically doing your own layout (cross-browser too!) will be worth the reflow gains you'll get.

The advantages of letting React and then the browser's layout do their own thing is that you'll be able to benefit from the optimizations they make. React is coming out with Fiber, their new reconciliation algorithm which will most likely help with some of the issues you may face. You'll lose all of these benefits by going at it alone.

Hopefully that all makes sense! Let me know if you have more questions.

Ben

Costigan commented 7 years ago

Ben, Thank you for your reply. That you didn't say "react is great for a lot of situations, but you should use xyz for your problem" is helpful. I'll try letting react do its thing as you suggest and the go on from there. Fiber should definitely help, especially delaying offscreen updates. Thanks again. - Mark