davedawkins / Sutil

Lightweight front-end framework for F# / Fable. No dependencies.
https://sutil.dev
MIT License
298 stars 19 forks source link

Elmish performance improvements? #78

Open reinux opened 1 year ago

reinux commented 1 year ago

Hey, thanks for sharing Sutil. I've been enjoying it a ton.

I happen to be writing something that requires a spreadsheet-like feature, and having come from Fable.Elmish, the spreadsheet sample happens to be a perfect reference for me.

But not surprisingly, performance seems to be quite slow, presumably because it has no shadow DOM and has to rebuild everything within a Bind.el.

Is there anything I can do to speed up MVU views? Or should I just switch to a reactive design?

davedawkins commented 1 year ago

I have an additional sample called Cells that addressed this very issue, that I disabled when I released Sutil 2.0, because the 2.0 changes broke it (rightly so, it was delving into the internals!).

I've fixed the broken change, and am just now messing around with it to fix the cell dependencies. I will post again here to let you know when it's done.

If you succumb to temptation and look at Cells before I post my updates, then keep in mind I'm reworking it and hope that it looks a lot more understandable with my updates.

davedawkins commented 1 year ago

(and thank you for your kind comments)

reinux commented 1 year ago

Cool, thanks!

davedawkins commented 1 year ago

Changes are checked in. Try this: https://sutil.dev/#examples-cells

I still think the reactive part of this example (lines 250-271) could be improved (for example, what's the meaning of CoreElements.subscribe? is it just badly named? Why isn't it just a Bind.el? etc) and I'll continue to look at it.

I'd be interested to know how the performance compares.

reinux commented 1 year ago

Nice, I'll try it against my own code tonight and report back. Thanks again!

reinux commented 1 year ago

Okay, this took me a little while to wrap my head around, but I see what's going on.

You're right that I can't think of a better way to express the subscribe parts. I guess it just seems a little weird because the need for these subscriptions doesn't feel like it comes from the data itself, but from a very specific set of changes in the data (hence the need for NeedsRefresh). I guess this is just a case where pure MVU is more conceptually straightforward.

On my reasonably fast desktop machine, the naive Elmish-only Bind.el call takes about 50ms for 12x242 cells. The rest of the 400ms or so is in rebuilding the DOM. I'd assume the reactive version is virtually instantaneous, though I'll get back to you as soon as I implement it.

I'm tempted to someday port Elm's virtual DOM to work with Feliz/Elmish, or better yet, made generic. It's a couple thousand lines of mostly js, though it might even be viable to port just the Elm wrapper portion of it.

For now, this will do the trick, and reactive style has its benefits anyway.

Thanks again!

davedawkins commented 1 year ago

It feels to me like writing DOM reactively is all about finding an optimal expression for the binding. It's manual optimization.

I've wondered about the Elm VDOM too. I hadn't thought of porting, but I had thought I could make Sutil build a simple VDOM and diff that with the existing DOM. You wouldn't need to be so precise with the reactive expressions then. In theory, you'd be able to rebuild the whole view on every MVU dispatch cycle, and we're back to where Elm is. I can't decide if there's a place for a hybrid like that or not.

Let me know how performance goes.