tmbb
LiveView performance problems - Morphdom taking up to 1500ms to patch updates
I’m writing a pretty basic application where users will be able to create “projects” for data entry purposes. A user can create a “project”, which contains a number of “tables”, where each table has a number of “columns” and columns can be of type choice, in which case each table will have a number of “choices”.
To simplify implementation and because I think that is a genuinely good UI, I want to be able to edit everything in the same page. I have the fields for the project, then I use (a customized version of) to create an editable list of tables, then another <.inputs_for/> to create a list of columns for each table, and then a list of choices for each column.
I expect each project to have 1-2 tables, and each table to have up to 60 columns, with some columns having up to 10-20 choices. For these numbers, the number of elements in the webpage is about 10.000. This creates a 4 levels deep stack of neste inputs, which seems like LiveView can’t optimize in any way. The result is that when I edit any of the hundreds of input components in the form, the changeset is recomputed and a rather large message is sent to Morphdom on the client. The elixir code doesn’t struggle at all with any of this, but Morphdom takes up to 1500ms to patch the updates (I’ve gotten these numbers from logs enabled by liveSocket.enableProfiling();).
Is this the kind of performance one is expected to get? Is there any way I can try to restrict which parts of the HTML dom morphdom actually tries to patch? I could break the tables and columns into different pages (with different liveviews, even), but that is not how I want the page to look like… One of the problem of breaking things up is that you lose the ability to render errors that depend on parts of the form interacting with each other (say we create two tables with the same name: my approach makes it trivial to tag that as an error in the changeset and display it to the user using the normal Phoenix components).
I’m honestly very surprised that morphdom’s performance is so bad on what doesn’t look like a very big page (~10.000 HTML elements, < 200 input elements). It seems like I’ve bought into the hype of thinking that LiveView would scale to moderately sized dynamic webpages, when in fact all examples I see of actual LiveViews are render extremely small web pages… Although Elixir definitely scales up to lots of events, the javascript seems like a serious bottleneck!
Most Liked
josevalim
And to be clear, that’s not necessarily a problem either, the tricky part is that those are dynamic branches. It seems you are updating a list with a dynamic list with a dynamic list with a dynamic list inside. This is neither common nor simple.
This should not be a concern payload wise, enable compression on the socket and you should be good to go.
In any case, looking at the above, it does make me wonder indeed if three level deep association in a single form is the best design and/or UX. I assume it can get confusing for the user to manage several levels of a hierarchy at once (I think this is the first time I see that many levels in a single form!) Someone already suggested to break the forms apart but you can also do something like this:
TABLE
[ Column EDIT DESTROY ]
[ Column EDIT DESTROY ]
[ Column EDIT DESTROY ]
[ Column EDIT DESTROY ]
[ NEW ]
Where the first level of management is not really a form but something that allows you to manage the children.
It also made me realize that, because you are validating the whole form and all associations at once as the user fills in, the validation on the server itself may become expensive too. It would be similar to an e-commerce platform where you have a single form for the categories, then products, then the variants, and then the images, all at once. I wouldn’t be surprised if another performance issue pops up even if the UI one is addressed.
Anything that runs on platform XYZ will, by definition, require you to care about XYZ at some point. At some point, an Elixir dev may need to care about the Erlang VM. At some point, you may need to care about Unix if you deploy to Unix. And, if you are running in the browser, at some point you will need to care about it too.
Btw, after thinking about this problem a bit, I was wondering if part of the issue is because the updates are mostly the same, the diffing is expensive because Morphdom is traversing everything mostly to find out that almost nothing changed. Similar to how comparing two lists for equality will be naturally more expensive if the two lists are equal. I am speculating here though. If someone has a way to reproduce this, I will gladly take a look. I quite enjoy optimization work!
olivermt
josevalim
I don’t think the list size is the issue but rather its contents. DOM is a tree and you are more likely being punished by the tree than the list size. Morphdom works by comparing node by node and using IDs may help it to avoid discarding changes.
Keep in mind you can track a lot of this in the Network tab already of the dev console, where you get payload sizes per WebSocket message, but it would be beneficial making this information more upfront too, so
.
Other than that, the comprehensions contents are sent as a whole if the comprehension changes, because computing the difference between two arbitrary lists can be resource expensive, so you need to resort to either LiveComponent or streams, as already explored. But these should be better documented. I will submit more docs later today.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex










