Open tomByrer opened 3 years ago
@tomByrer This issue is hard to measure.
What time slicing improves is response performance, which can make your page no longer blocked.
However, the total time of page rendering is longer than that of synchronous rendering (such as Inferno).
So it's unfair for fre to just measure the rendering time.
Can you understand me?
I refactor the algorithm again, and then used a new technique called ofscreen rendering
This is a technology similar to DocumentFragment
. It operates DOM in memory and finally paints to the screen at final time.
Now fre is super fast, even faster than vanilla js.
Oh wow, cheers!
cc @ryansolid , Hey my friend, I saw your reply on twitter. My country forbids me to login twitter. I want to reply to you here.
This optimization is also called Offscreen rendering
. It was inspired by IOS UIkit / Opengl and so on.
Fre operates DOM in memory and paint them to the screen once at the last time.
https://thoughtbot.com/blog/designing-for-ios-graphics-performance
I haven't used the DocumentFragment
API, just that their ultimate behavioral results are similar.
I generate an effect list in reverse order in the reconcile phase, and insert them into the screen in reverse order in the commit phase.
This is a pure data structure and algorithm optimization.
Of course, Fiber structure and two-phase traversal do provide convenience, but other singlepass frameworks (such as Vue or preact) are not completely impossible to implement this algorithm.
It is worth mentioning that offscreen rendering is an optimization during the commit phase, It has little to do with concurrent mode, and time slicing is not necessary.
To be clear I don't doubt the algorithmic/scheduling improvement. Just when people say faster than vanillajs, some clarification is needed as vanillajs(hand crafted and optimized for the specific solution) by its very nature should be the fastest. So generally I treat that claim with skepticism.
its very nature should be the fastest. So generally I treat that claim with skepticism.
The runtime algorithm with off-screen rendering is faster than vanillajs without off-screen optimization. Maybe it’s more appropriate to say that?
@ryansolid
In order to verify the results, I tested again. I was an i7 7700k windows computer, using an M6000 graphics card.
The actual test of fre off-screen rendering has been faster than vanillajs, while solidjs and vanillajs are almost the same.
I tested on another low configuration computer and found that the fre off-screen rendering still can be close to vanillajs , which is much better than other vdom frameworks.
Where/what is this test? When you say offscreen rendering are you also including the cost of applying it on screen. If JS Framework is no good to show this off.. maybe like UIBench(https://github.com/localvoid/uibench)? Its basically tailored for comparing VDOM reconcilers.
EDIT: What is particularly good about it is it can measure the pure reconciler time or the time + paint. I usually ignore the non-paint scores but it can be useful to look at our algorithm speeds. One of the weirdest things about Solid is the non-paint times are slower comparatively to VDOM libraries, but when you add the paint in suddenly things are much closer. I'm gathering it is because the way it is measured and Solid's use of synchronous updates. Solid literally mutates the DOM immediately so even if we aren't capturing paints you would be capturing DOM mutations. Anyway I digress. This is probably a better comparison with peers.
I went ahead and built out a benchmark:
https://github.com/krausest/js-framework-benchmark/compare/master...mindplay-dk:fre2-keyed
Apparently it's the second time I've done that, but I forgot, haha - this one is a bit cleaner though, with a simpler Rollup build.
Unfortunately, the latest published release 2.2.0
appears to have a console.log
statement in it. 😬
@yisar can you publish a fresh release, please? (the console.log
statement is present in the dist/fre.js
but not in the source files, so you probably did this accidentally while debugging...)
I've only been able to run it by manually entering the URL after manually building - I don't have all the system dependencies set up, and the instructions in the README didn't work for me, I think they're outdated.
@ryansolid presumably you have it running? Maybe you can pull my branch and try it? so we can see what's what. 🙂
@mindplay-dk v2.2.1 has been released. You can see the specific forces here https://github.com/yisar/fre/blob/master/demo/src/benchmark.tsx
@mindplay-dk As last time, this test seems unable to accurately test the framework with time slicing. Almost all frameworks use microtask.
@mindplay-dk I played the benchmark this afternoon today, but it seems to be slower than expected. Next, I will make some adjustments for the test. At present, it seems that we should do diff props in advance, not here: https://github.com/yisar/fre/blob/master/src/dom.ts#L4 Wait for me.
There's a lot of improvements to be made:
https://github.com/yisar/fre/blob/master/src/dom.ts#L9 prefix and suffix spread is usually slower than a single Object.assign call (around <100% slower, specially on chrome)
https://github.com/yisar/fre/blob/master/src/schedule.ts#L19
https://github.com/yisar/fre/blob/master/src/reconcile.ts#L229-L230
forEach
is normally slower than for-increment (>90%, Chrome)
https://github.com/yisar/fre/blob/master/src/schedule.ts#L39 queue shifts is usually slow
https://github.com/yisar/fre/blob/master/src/h.ts#L20 concat is slower than spread-on-empty-array (70% slower, Chrome)
https://github.com/yisar/fre/blob/master/src/h.ts#L8 Can be simplified, filter is usually slower than double slice call (60% on 1000+ elements, Chrome)
Still trying to find some core issues. To summarize, most FP methods of arrays are generally slow due to spec-related implementation. It would be better if you can implement/simplify your own array transformations just to provide faster paths. I may be wrong on some of the details I provided, feel free to rebench.
@LXSMNSYC Thank you. You're right, but the most important thing is to implement fre.memo
This is more important for that benchmark use case.
This is also the reason why fre slows down. Especially when the speed is reduced by 16 times.
You said that the optimization of codes is also very reasonable. I will modify them slowly. Thank you!
Yes. That's one of the issues with Vue before up until 3.2 when they decided to introduce v-memo. If you can implement that then that would provide a lot of render skip process.
Is this a regression, or does Fre really use that much more memory and take that long for a partial update?
No, the current benchmark performance metrics for fre are mainly due to the fact that the fre.memo
API is not implemented, resulting in thousands of duplicate component updates.
https://github.com/krausest/js-framework-benchmark/blob/master/frameworks/keyed/react-hooks/src/main.jsx#L67
Very interesting take on JSX!
Would be helpful to compare performance: https://github.com/krausest/js-framework-benchmark I'm guessing a bit better than Inferno?
relevant discussion