intercellular / cell

A self-driving web app framework
https://www.celljs.org
MIT License
1.5k stars 93 forks source link

performance? #17

Closed leeoniya closed 7 years ago

leeoniya commented 7 years ago

Hi @gliechtenstein

I noticed you don't have any benchmarks to compare with other frameworks and don't mention anything about cell's performance. Would you be interested in submitting an implementation of js-framework-benchmark? I'm curious where it would land in the table [1] and even more interested if the actual implementation would be as simple as the docs claim.

BTW, not all dom libs require build tools or extending framework classes ;) [2] [3]

cheers!

[1] https://rawgit.com/krausest/js-framework-benchmark/master/webdriver-ts/table.html [2] https://github.com/leeoniya/domvm [3] https://github.com/thysultan/dio.js

ninive commented 7 years ago

Hi guys, first of all - very nice idea, I really like this approach.

Since I have a good experience with Mithril.js and virtual dom in general, I run a quick preliminary test based on this page from Leo - https://mithril.js.org/framework-comparison.html

Compared to React, it shows impressive results. Even Mithril seems slower generating 10000 divs+nodes.

Fiddles here for brevity: https://jsfiddle.net/bfoeay4f/ - https://jsfiddle.net/fft0ht7n/ Here's my simple code you can test in your browser.

<html><script src="https://www.celljs.org/cell.js"></script>
<script>
console.time("total")

let list = Array.apply(null, Array(10000))
    .map(function (x, i) {
        return i
    });

Node = function(){
  return { $type: "div", $text: "hi"}
}
var Bench = {
  $cell: true,
  $components: list.map(Node)
}
console.timeEnd("total")
</script></html>

Please let me know your feedback, thanks! ;)

guscost commented 7 years ago

This is not an accurate benchmark unfortunately (it would have pretty absurd performance if those numbers were real).

To get the proper "render" time, the cell has to be built first. In your example, the cell application internally is starting up on the window's load event, but you've already logged out the total time before then.

Here's a benchmark that logs the end time in an event hander instead:

https://gist.github.com/guscost/0e21a65e1752a7efa6ee84d2e9cd4c81

It takes almost 900ms, which makes much more sense. This isn't a speedy production UI platform like some of the bigger projects, not yet at least. It is possible that the choice to work "close" to the real DOM puts an ultimate ceiling on performance as well.

ninive commented 7 years ago

Hi Gus,

thanks for the feedback, I was briefly testing now converting some modules from Mithril and realized wasn't that fast. The Fiddle made the trick and I forgot about the listener, sounded strange ;)

Anyway, this is pretty new and for sure being that "close" to the real DOM probably isn't that fast as the Mithril diff sync render. The approach is not so far though so I think that's a lot of potential on optimizations.

Keep up the good work, I'm gonna play with it tonight.

guscost commented 7 years ago

It looks like the startup sequence (scan for cells and start up everything) might lend a lot of time to the benchmark, but there's definitely some significant resource usage to render a big list.

ninive commented 7 years ago

Totally agree, due to decentralized design bind/update, I think a percentage is on the rAF ticker latency, part is on the scripting resources.

Being another decision path on how to handle the routing, I've tested a converted real world app with less than 60 nodes per page, and Mitrhil is still 2.5X faster.

Apart from optimizations, Cell fits also perfectly to handle the scheme advantage to "in-design" canvas UIs and be implemented easily in node->flow (Blender like) programming technique in learning industries.

I'll keep playing, let me know what you guys think thanks.

gliechtenstein commented 7 years ago

Late to the party, but first of all thanks for trying out all these tests!

You guys are right that Cell's main selling point is not performance (yet) but about enabling a different way of structuring an app.

In fact I really didn't put much time into optimization yet because I've been 100% focused on how to structure the low level architecture, and there's already been at least one contribution that improved the performance significantly (thanks @SeHeGit)

Technically, I don't think there's any reason why Cell shouldn't be faster than any existing frameworks, it's just that it's not been the focus while I was working on it, so we just need to "evolve" the library a bit if we want to improve this.

If you guys find a way to improve performance please don't hesitate to send pull requests or open an issue for discussion. Thanks!

gliechtenstein commented 7 years ago

Closing since there's not much to be done about this at the moment. I'll make sure to update this thread when there's a news or something actionable. Thanks!

gliechtenstein commented 7 years ago

Hey guys just an update. Like I brought up earlier, even though the performance is not the focus of this library, I can't see any reason why Cell should be slow, since it's just using a regular DOM but not touching any of the attributes directly.

So I took a look at it a bit. I didn't spend too much time but I could at least find one instance where it's doing unnecessary things that were causing some performance problems. https://github.com/intercellular/cell/commit/24b77e803d6de15ce6b6641b520ff78221ab4117

The result is the same test case mentioned above goes down all the way to somewhere between 160 and 190ms on average. https://jsfiddle.net/4brjeprn/

It's literally just one line and I'm sure there are many other cases where optimizations can be made. I've finally added comments to the code https://github.com/intercellular/cell/issues/137 so it should be easier to understand what's going on. So if you anyone plays around with the code and comes up with improvement feel free to send PR or share. Thanks

leeoniya commented 7 years ago

node creation is probably the least interesting metric because there's 0 complexity in a simple createElement/appendChild loop. it's the mutation logic which needs validation.

ninive commented 7 years ago

@gliechtenstein thanks a lot for the update mate, again it's a very good concept. As I wrote above, it really feels like a strong minimal "framework" to be applied in a flow-controlled environment (especially in code learning), fits perfectly. Proper routing and a new diff engine can make it jump, but I personally like it simple as it is.

@leeoniya you're right, but that's not totally true. While having 0 complexity any diff engine is still exposed to a buffer->video rendering. This is still valuable and tries to give you numbers and understand how much you can scale up. On the other side, there are more complex benches that can be explored anytime, like those two that are React and Mithril on Ember and we can follow up anytime if we would like to. And it's also valuable to notice the easy learning curve of Cell, including his own complexities.

http://cdn.rawgit.com/MithrilJS/mithril.js/master/examples/dbmonster/react/index.html http://cdn.rawgit.com/MithrilJS/mithril.js/master/examples/dbmonster/mithril/index.html

leeoniya commented 7 years ago

if you look at the table [1], you'll see that create rows is not always a strong indicator for overall perf. react-lite-v0.15.30 (keyed) and choo-v5.4.0 (non-keyed) both show great numbers in that metric while landing at or near the bottom overall.

dbmonster is no longer a great bench. it only shows that you're not slow, but it doesn't show that you're fast. it's a good regression test in that respect and i use it frequently [2]. dbmonster tests only very simple/linear reconciliation patterns and minimal mutation (only className and textContent/nodeValue)

create rows is the same, it's a good sanity check, but hardly representative.

[1] https://rawgit.com/krausest/js-framework-benchmark/master/webdriver-ts-results/table.html [2] https://rawgit.com/leeoniya/domvm/3.x-dev/demos/bench/dbmonster/index.html

ninive commented 7 years ago

At first, I had a look on your repo, and domvm sounds great, thin great work.

Sorry I'm traveling got a bouncing network ;) I would like to point out on being myself too much into the performance issues whenever this approach could be completely different from what a pure virtual DOM could be. For sure it's on traversing and I'm with you with dbmonsters but still, imagine having this in a canvas node pattern where any x ↦ f (x) is available drag&drop and still real-time.

Happy to listen what you guys think.