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]> 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]> 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]> 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? >> >
