FWIW, the time spent in JS is only telling half the story. In that first example, React spends half as much time painting and rendering as Vue; the DOM diffing is more js-time intensive but results in less DOM thrashing. Interesting to watch how poorly it seems to scale; I'm wondering if web workers in future React versions will change that story.
In case you missed it, the author confirmed the tests were accidentally using the development version of React, which is significantly slower due to the additional warnings and sanity checks. The actual results seem to be much less surprising.
At Discord we've actually spent a bit of time optimizing around frequently updating tables of data.
On the extreme end of things, we have lists that contain several thousand items that update a few elements that are potentially updating up to ten times a second. The biggest being the member list on a server. One of our servers has ~6500 online right now, with people coming online/offline/away every second, changing their current game, typing, etc...
Few lessons we've learned:
1) Don't use ImmutableJS for small objects with a few keys containing scalar values, it's too slow. It's actually faster to just a) copy objects ({...oldValues, newKey: newValue}) or b) re-use objects and power shouldComponentUpdate in another fashion. In some cases, we use an "object version" that is incremented every time the object is actually updated. Then compare that in shouldComponentUpdate.
2) Only render what's visible. In our lists, each item has a fixed height, so we only render elements that are visible. This cuts down from having to render 6500 items in that list, to a good 20-30.
Yep, the test is considering all the calls to get() and getIn() as part of the React render overhead but these methods are much slower than accessing properties directly. Running a comparison after removing the ImmutableJS state and adding version tags to the players (the game object can use its "clock" as a version), the production React implementation seems about twice as fast (1518 ms for React, 3377 ms for Vue, not at all scientific though).
Note: Using version tags with shouldComponentUpdate is a great way to optimize for speed, but then you're responsible for updating all your versions manually. If you forget one, the component will "freeze" and you may spend some time tracking down the problem. Just a friendly reminder that immutable data and unoptimized components are both better in this respect.
OK on a different computer I'm seeing 768 ms for React and 398 ms for Vue. Maybe I got the tests backwards before. Or maybe there is that much variability. I'll have to check again.
') Only render what's visible. In our lists, each item has a fixed height, so we only render elements that are visible. This cuts down from having to render 6500 items in that list, to a good 20-30.'
You're definitely right to point out that Immutable.js is really not always what you want for small values that change all the time. Immutable.js collections are best used for just that: collections. If you have to copy an array or map with a ton of entries to make a change, it's going to be super slow - Persistent Immutable data structures can help with that.
But I agree with your conclusion that any JS objects that are being used as small tuples are definitely better off staying plain JS objects.
You also don't have to use all Immutable.js or nothing at all. Similar to how using an ES6 Map collection means you don't have to stop using JS objects. Use Immutable collections where they offer benefits, but spreading it everywhere is not a performance panacea, as you rightly discovered.
When I was typing out the original reply, I meant to say "Don't use Immutable.JS for small objects" but ended up putting a period in the middle... which could have led to some confusion. I've edited it to make it more clear.
We've also had some perf issues with using Immutable JS for even larger arrays. I think paying the cost of shallow copying the entire array when modifying it ended up winning in the long run as our render functions could loop over the array much faster.
I'm curious how you keep track of visibility? I have a React app that does something similar to this by checking on scroll, but I kept getting killed by the browser having to check layout so many times on scroll, even if I throttled the event listener.
Since our elements have fixed height, we just do some simple maths in JS land to compute what should be visible, rather than measuring stuff using the DOM (which forces layouts).
I often point people to icepick which is a tiny library for working with immutable data in plain JS objects. It's a nice fit for when Immutable.js is too heavy
On that note, I've got a page devoted to immutable-data-related libs in my Redux addons page. Lists a couple purpose-built structure libs (Immutable and Mori), several data libs built around freezing, and a whole bunch of utility libs that provide abstractions around immutably updating plain objects: https://github.com/markerikson/redux-ecosystem-links/blob/ma... .
You're unfortunately not the only one that doesn't use prod for doing benchmarks and potentially also not for actual production. If you have ideas on how we could better educate people about the difference, I'd love to know. https://twitter.com/Vjeux/status/735178192651063298
I don't have any suggestions regarding education, but it would be helpful for me (and I'm sure others) if there was a non minified production build available via bower; My build process isn't using npm modules right now, so I've been stuck using the dev version.
I'm intrigued as to whether that would make a difference overall and whether there is any difference between the frameworks when using ABP.
Difference is likely insignificant, but if React is not touching the DOM unless it needs to, does it actually lead to a performance benefit when a user is running an ad blocker (constantly parsing page changes etc).
You should compare a plain JavaScript object (use shallow or deep compare if you must) version against Vue.
I'm sure Immutable is pretty well optimized, but you still have overhead from all those function calls and iterating through the array of keys manually.
Exactly this. Immutable is for collections, e.g. maps, sets, lists. The objects in the example are just objects, they are not maps. Using Immutable is just a pointless complication.
One of my coworkers wrote and maintains an amazing library called react-virtualized [0], which can be of help for certain similar cases in which you have to render huge amounts of data. You just avoid rendering anything outside of the viewport.
And this, children, is why we do a proper job. Because the JS landscape nowadays looks like a house of cards, with people who can't code treating modules like Lego to build things.
Web dev has exciting things going on in it, but it feels mostly like a bunch of children with no concept of consequences running around desperately re-inventing wheels, rather than caring about quality, efficiency, diligence and professionalism.
It's fucking disgraceful, and we should be ashamed of it.
I just read another article here in HN how someone learned how to program (JS/Ruby/HTML and web things..) and got a job in web development in 5 months. I guess it says all about the current quality of this subfield. Unfortunately for me, I've been "selling" myself as full-stack web developer, so I think I'm screwed..
I've been playing with electron (unfortunately based on Node), and the "npm install" installs a lot of 20 line node packages to do really small things. I think these guys took the unix philosophy of do one thing and do it right to such an unpractical extreme.. But I guess that you can't do any better when all your formal studies were 5 months in codeacademy and the like..
29 comments
[ 5.9 ms ] story [ 33.6 ms ] threadhttps://github.com/footballradar/VueReactPerf/pull/3
On the extreme end of things, we have lists that contain several thousand items that update a few elements that are potentially updating up to ten times a second. The biggest being the member list on a server. One of our servers has ~6500 online right now, with people coming online/offline/away every second, changing their current game, typing, etc...
Few lessons we've learned: 1) Don't use ImmutableJS for small objects with a few keys containing scalar values, it's too slow. It's actually faster to just a) copy objects ({...oldValues, newKey: newValue}) or b) re-use objects and power shouldComponentUpdate in another fashion. In some cases, we use an "object version" that is incremented every time the object is actually updated. Then compare that in shouldComponentUpdate. 2) Only render what's visible. In our lists, each item has a fixed height, so we only render elements that are visible. This cuts down from having to render 6500 items in that list, to a good 20-30.
Here's the implementation without ImmutableJS:
https://github.com/guscost/VueReactPerf
Note: Using version tags with shouldComponentUpdate is a great way to optimize for speed, but then you're responsible for updating all your versions manually. If you forget one, the component will "freeze" and you may spend some time tracking down the problem. Just a friendly reminder that immutable data and unoptimized components are both better in this respect.
silly me! Apologies!
You're definitely right to point out that Immutable.js is really not always what you want for small values that change all the time. Immutable.js collections are best used for just that: collections. If you have to copy an array or map with a ton of entries to make a change, it's going to be super slow - Persistent Immutable data structures can help with that.
But I agree with your conclusion that any JS objects that are being used as small tuples are definitely better off staying plain JS objects.
You also don't have to use all Immutable.js or nothing at all. Similar to how using an ES6 Map collection means you don't have to stop using JS objects. Use Immutable collections where they offer benefits, but spreading it everywhere is not a performance panacea, as you rightly discovered.
When I was typing out the original reply, I meant to say "Don't use Immutable.JS for small objects" but ended up putting a period in the middle... which could have led to some confusion. I've edited it to make it more clear.
We've also had some perf issues with using Immutable JS for even larger arrays. I think paying the cost of shallow copying the entire array when modifying it ended up winning in the long run as our render functions could loop over the array much faster.
I'm curious how you keep track of visibility? I have a React app that does something similar to this by checking on scroll, but I kept getting killed by the browser having to check layout so many times on scroll, even if I throttled the event listener.
https://github.com/aearly/icepick
We'll re-run the tests in the morning (uk) and post the updates.
Good to know react isn't as bad as how it's painted here! (I'll see myself out).
I'm intrigued as to whether that would make a difference overall and whether there is any difference between the frameworks when using ABP.
Difference is likely insignificant, but if React is not touching the DOM unless it needs to, does it actually lead to a performance benefit when a user is running an ad blocker (constantly parsing page changes etc).
I'm sure Immutable is pretty well optimized, but you still have overhead from all those function calls and iterating through the array of keys manually.
[0] https://bvaughn.github.io/react-virtualized/
Web dev has exciting things going on in it, but it feels mostly like a bunch of children with no concept of consequences running around desperately re-inventing wheels, rather than caring about quality, efficiency, diligence and professionalism.
It's fucking disgraceful, and we should be ashamed of it.
I've been playing with electron (unfortunately based on Node), and the "npm install" installs a lot of 20 line node packages to do really small things. I think these guys took the unix philosophy of do one thing and do it right to such an unpractical extreme.. But I guess that you can't do any better when all your formal studies were 5 months in codeacademy and the like..