How a Readonly Property Wrecked My Letta Desktop Performance

Are you telling me a readonly property is wrecking my performance?

I discovered that a simple script using scrollHeight to auto-scroll new messages in Letta Desktop was causing severe slowdowns. I assumed this readonly property was static and fast, but accessing it forces expensive layout recalculations every time. Instead of calculating the exact height, I switched to a large fixed number to maintain performance.

I just assumed that readonly properties will always be pretty performant in general.
  1. stinos

    Even without this performance hit, an often used way for implementing 'auto scroll to top/bottom' is to first check if there's no other stuff coming in before starting to actually scroll. This goes unnoticed by the user but drastically reduces the number of updates (and in this case, number of calls to scrollHeight) needed when a lot of data is coming in in batches. Principle is like: receive message, add to buffer and start timer of like 50ms. Upon timer tick copy everything from buffer (which in the meantime can have accumulated more data) to rendering and only then update scroll.

  2. Groxx

    Yup. Anything layout-related could be costly to read, and could force a layout to occur if modified since the last read (even within the same synchronous javascript code). Most things are not deferred until the next layout pass, which is one of the reasons virtual DOM got popular: it batches changes for you.

  3. francisofascii

    If scrollheight is not a performant property, than it shouldn't be a property. It should have been a method called calculateScrollHeight() or something to indicate that it is not cheap.

  4. gblargg

    Properties are to allow dynamic actions for what appear to be simple variable accesses. They don't magically make those as fast as accessing a variable; they are a syntactic convenience to allow assignment and using the value implicitly rather than having to invoke a function/method. They could have cached the value and kept a dirty flag, but then everything that affected the value would have to be sure to mark it as dirty or result in subtle bugs.

  5. blixt

    The biggest performance bomb you can have in your code is a loop that does something like

    for (...) {

    el.style.height = `${something}px`;

    whatever.value = el.style.offsetHeight;

    }

    This forces the browser to recalculate layout multiple times in a single frame. Separating layout changing code from measurement code will help a lot here (most frameworks out there have solved this so we don't have to be too concerned about it though).

More from this day

2026-07-13