Hi Harbs, As I see your major changes is adding _explicitHeight/width and this queue. Am I understand right all ? Which one actually helps so much ? Adding _explicitHeight/width or that queue ?
Thanks, Piotr 2018-03-24 22:04 GMT+01:00 Harbs <[email protected]>: > 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 <[email protected]> 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 <[email protected] > <mailto:[email protected]>> 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" <[email protected] <mailto: > [email protected]>> 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" <[email protected] <mailto: > [email protected]>> 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? > >>> > >> > > > > -- Piotr Zarzycki Patreon: *https://www.patreon.com/piotrzarzycki <https://www.patreon.com/piotrzarzycki>*
