tmbb

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

josevalim

Creator of Elixir

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

olivermt

Throw everything into live components. Little bit more memory, much better diffs.

josevalim

josevalim

Creator of Elixir

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 :+1:.

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.

Where Next?

Popular in Questions Top

sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lists...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

Other popular topics Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 31194 112
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 39523 209
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New

We're in Beta

About us Mission Statement