royale-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Harbs <harbs.li...@gmail.com>
Subject Re: Layout optimizations
Date Sat, 24 Mar 2018 21:04:16 GMT
I just pushed some changes to a layout-optimization branch.

I’m seeing about a 5 *times* improvement in performance with layouts and I don’t see any
issues with the layout. It seems to me like this optimization was a lot more painless than
I feared.

Where I was seeing a layout take about 150 ms, it’s not taking about 30 ms. The only place
I’m seeing the dreaded "Forced reflow” warning now is in my own code where it needs optimization.

I don’t see any down-side to the code I committed, but I’ll wait for feedback before I
merge it in.

Harbs

> On Mar 24, 2018, at 10:17 PM, Harbs <harbs.lists@gmail.com> wrote:
> 
> This is all good info.
> 
> Here’s the problem as I see it:
> 
> 1. Measuring width and height cause reflows if css properties were set and/or the Dom
structure was changed.
> 2. EVERY layout reads the host width and height before and after layout. Every layout
(currently) subclasses LayoutBase.
> 3. It’s pretty unlikely for any layout so not set some property, so what happens in
#2 will cause a reflow every time unless the width and height is explicitly set (using a modification
to the width and height getters).
> 
> I’m looking to solve this by the following:
> 1. Optimize the width and height getters to return the explicit values if they exist.
In my case, this seems to yield about a 10% improvement. That’s not bad, but I think we
can do much better.
> 2. Delay the layout until the entire DOM structure is measured.
> 3. The measuring might also need to be delayed until the whole structure is created.
> 
> Basically, I want to make a measuring stage and then a setting stage. I’m not sure
whether I should use requestAnimationFrame or some other method. The trick will be getting
the measurements and the layouts executed in the correct order.
> 
> Some links on the topic:
> 
> http://blog.fogcreek.com/we-spent-a-week-making-trello-boards-load-extremely-fast-heres-how-we-did-it/
<http://blog.fogcreek.com/we-spent-a-week-making-trello-boards-load-extremely-fast-heres-how-we-did-it/>
> http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/ <http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/>
> http://wilsonpage.co.uk/preventing-layout-thrashing/ <http://wilsonpage.co.uk/preventing-layout-thrashing/>
> 
> I’m planning on spending time on this tomorrow. I’ll see what I can come up with…
> 
> Harbs
> 
>> On Mar 23, 2018, at 7:11 PM, Alex Harui <aharui@adobe.com.INVALID <mailto:aharui@adobe.com.INVALID>>
wrote:
>> 
>> Hi Harbs,
>> 
>> For sure, it would be great for you to take a look at layout.
>> 
>> Besides what Peter wrote below, there are other things to consider:
>> 
>> 1) Like Flex, Royale layouts assume that (when necessary) parents size
>> their children.  That just makes sense for responsive apps that respond to
>> the size of the application window.
>> 2) Like Flex, Royale's UIBase has APIs that "temporarily" set a size.
>> Setting width/height also sets explicitWidth/explicitHeight, but the
>> setWidth/setHeight/setWidthAndHeight calls only set the width/height and
>> do not set explicitWidth/explicitHeight in order for that layout pass to
>> set the size but not have the explicitWidth/Height factored into the next
>> layout pass.
>> 3) The code snippet you posted I'm pretty sure is used for when a child's
>> size changes and the parent's size should then change.  As Peter said,
>> some components are sized to content and the layout should be responsive
>> to the content.
>> 
>> But what I think is most important is really what the DOM looks like.  The
>> only goal for Royale layouts for JS is to set up the DOM.  In theory, the
>> default VerticalLayout and HorizontalLayouts do not measure anything nor
>> do they set the width and height on the children.  They merely set the
>> display style to block or inline-block.  Then it is up to the browser to
>> decide when/how to layout.  Ideally, our JS code is creating widgets and
>> setting display styles in the most optimal way to create the same DOM you
>> would by hand with an HTML editor.
>> 
>> So, for your app, the first question is: did Royale set up the DOM in the
>> best possible way?  I think you said there was a fair amount of absolute
>> positioning in your app.  If the Royale absolute positioning layout is not
>> allowing the construction of the DOM in the best possible way, the next
>> question is then: should the current layout algorithm be changed because
>> it is just plain wrong, or should you create a different absolute
>> positioning layout that is optimized for the kinds of DOM sub-trees you
>> like to use?  Or should you be revising your app to use a layout based on
>> FlexBox or CSSGrid?
>> 
>> So, it might turn out that BasicLayout is always going to be slow but it
>> will handle just about any absolute positioning from both top-down
>> percentage sizing as well as sizing to content of children, but that new
>> layouts should be created that drastically reduce the number of folks that
>> need to use BasicLayout in production.
>> 
>> My 2 cents,
>> -Alex
>> 
>> On 3/23/18, 7:25 AM, "Peter Ent" <pent@adobe.com.INVALID <mailto:pent@adobe.com.INVALID>>
wrote:
>> 
>>> The code looks familiar, but I'm not 100% sure.
>>> 
>>> The trick with layouts is that there are the following things to consider:
>>> 
>>> If everything has an explicit width/height, it should be pretty easy.
>>> 
>>> The percentWidth/height when present changes the _width, _height without
>>> changing the explicit size. This allows a layout to work again on the
>>> percent value and calculate a new size. If the explicit sizes are set,
>>> then the next layout pass will take the explicit over the percent (setting
>>> explicit sizes sets the percent sizes to NaN and vice-versa) and what was
>>> once 50% will now be fixed in size.
>>> 
>>> The tricky part - for me anyway - is when an item has no size set. Then
>>> its supposed be sized by its content. Labels and Buttons sized by their
>>> text or icons while containers are sized by their children and so forth.
>>> 
>>> Let's say you have one container nested inside of another and in the inner
>>> most container is a single button. The outer most layout cannot determine
>>> its container-child's size because it doesn't have one yet. The inner
>>> container needs to get the size of its children (the button) and that then
>>> becomes its size. But it should not be setting the explicit sizes. That
>>> allows the button to be resized which means its container becomes bigger
>>> which means the outer container becomes bigger. Once you set those
>>> explicit sizes, then its game over - use case #1 essentially.
>>> 
>>> So - I think that code has to do with determining size-by-content and so
>>> isLayoutRunning was created to prevent a recursion.
>>> 
>>> For me, working with Flex and Royale - determining the size of something
>>> has been one of the biggest challenges.
>>> 
>>> ‹peter
>>> 
>>> On 3/23/18, 7:46 AM, "Harbs" <harbs.lists@gmail.com <mailto:harbs.lists@gmail.com>>
wrote:
>>> 
>>>> I¹m working on making layouts more efficient. Currently, there¹s lots of
>>>> setting and reading of width and height which causes many browser
>>>> reflows. While profiling performance in my app, reflows is a major
>>>> bottleneck. In one area, it¹s taking about 150ms (on my I7 2.8 Ghz
>>>> MacBook Pro ‹ on tablets it¹s painfully slow) to execute on area of
>>>> layout. Almost all of that time is being spent measuring with and height
>>>> of components. The width and height getters trigger reflow because
>>>> properties are recursively set in layout.
>>>> 
>>>> I was able to get about a 10% improvement by optimizing the width and
>>>> height getters to return the explicitWdith and explicitHeight if set. It
>>>> looks to me like almost all of this bottleneck could be eliminated by
>>>> delaying the property setting until after the measurements are done. I¹m
>>>> working on doing that, but I have a question:
>>>> 
>>>> LayoutBase.performLayout has the following code:
>>>> 
>>>> 					// check sizes to see if layout changed the size or not
>>>> 					// and send an event to re-layout parent of host
>>>> 					if (host.width != oldWidth ||
>>>> 						host.height != oldHeight)
>>>> 					{
>>>> 						isLayoutRunning = true;
>>>> 						host.dispatchEvent(new Event("sizeChanged"));
>>>> 						isLayoutRunning = false;
>>>> 					}
>>>> 
>>>> Under what circumstances does this code get executed? This appears to be
>>>> causing a recursive layout. Can I assume that there will be an
>>>> explicitWidth/height when this will be executed?
>>> 
>> 
> 


Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message