Expected performance for rendering 1000s of custom elements?

334 views
Skip to first unread message

al...@streak.com

unread,
Sep 3, 2015, 5:27:34 PM9/3/15
to Polymer
I'm trying to determine if the rendering performance I'm seeing with a page with 1000's of custom elements is expected or not. 

Here's an example I put together: http://codepen.io/anon/pen/GpgmQV which has a few thousand custom elements. You'll notice that the render (i.e. after all the assets have downloaded) takes anywhere from 2-6 seconds (see chrome profiler output: http://i.imgur.com/F8nhHPA.png). It looks like most of this time is spent with polymer creating and adding the custom elements to the page. Is this expected?

p.s. The obvious question is why would you have 1000's of elements on a page but lets ignore that for now.

Eric Bidelman

unread,
Sep 4, 2015, 12:10:48 AM9/4/15
to al...@streak.com, Polymer
I've been interested in this topic as well.


I'm seeing 5591 custom elements being created on that jsbin (see bookmarklet below). That's a lot! This is because
some elements create other sub custom elements in their shadow dom.  It's important to keep in mind that custom elements do more than plain-o-<div>. They don't come without costs. You're creating shadow dom, composing others elements, running lifecycle callbacks, doing layout, style recalc....

My first recommendation is to create fewer element instances. We're actually told by the Blink engineers that 1000 elements is the budget. That's not a lot, but 5k+ is way more than you ever should create on page load.

On the Polymer side, we're looking at perf optimizations like the one that recently landed in <iron-icon>. Basically, every instance of <iron-icon> was creating an <iron-meta> child. The new version (not the one you're using) creates a single instance of <iron-meta> that's shared across all instances of <iron-meta>. That makes a real difference if your page is using a ton of icons.

 chromestatus.com case study

Debugging chromestatus.com loading perf, I found there were 4000+ elements being created on page load. Each of the 356 feature elements in the list produced many sub elements. The solution was to create fewer instances up front. The way I did that was to use <iron-list> and selectively use <template is="dom-if"> to generate DOM only when I needed it (e.g. when the user scrolls the page or opens a feature panel). It was silly to generate that much DOM on upfront. 90% wasn't visible to the user.

Tools 

Justin has been developing a Chrome Extension that will be useful here. It will show per element metrics and answers questions like "What is the cost of putting this element on my page?" If you want something now, I created a bookmarklet that may be helpful. It records interesting numbers to the console.

Lastly, we've also been talking to the DevTools team to see what information we could expose to developers. If you have any ideas, please let us know!

Eric

Follow Polymer on Google+: plus.google.com/107187849809354688692
---
You received this message because you are subscribed to the Google Groups "Polymer" group.
To unsubscribe from this group and stop receiving emails from it, send an email to polymer-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/polymer-dev/8af8f0be-434d-4a8f-b8b7-5c60cf2559b8%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Aleks Totic

unread,
Sep 4, 2015, 12:11:17 PM9/4/15
to Polymer, al...@streak.com
1000 elements budget is stingy for single-page apps. Do hidden elements count against the budget?

Polymer's coding style encourages using lots of elements ("there is a component for that"). 

Number of elements component uses is unknown to the developer, until you inspect the dom. Usually, it is surprisingly high (10 elements for paper button).

Aleks

Aleem Mawani

unread,
Sep 4, 2015, 12:56:57 PM9/4/15
to Aleks Totic, Polymer

Thanks for the info. Here's a screenshot of my real ui (ci build server).

Screenshot 2015-09-04 09.39.25.png

On screen I'm only displaying 3 builds and that still results in 348 polymer elements and roughly 900 regular Dom elements being created at page load. Thats about 120 polymer elements for each of those builds. The performance is ok with just 3 builds.

Ideally my ui shows 50 of these builds in a scrolling list. It seems that even when using an iron list, it creates several extra items for buffering and the render delay then becomes noticeable.

Can you explain a bit more what you meant by hiding list items behind a dom-if? Isn't that the point of the iron-list, that it won't create many list elements because it only creates enough to fill the viewport plus some buffer. How does the dom-if help?

Any ideas to reduce the rendering time in general?

Summary:

1) How does the dom-if help?

2) Ideas for reducing the number of items created or lowering the initial render time?

3) Any idea when that improvement to iron-icons will be released. We use a lot of icons :)

Eric Bidelman

unread,
Sep 4, 2015, 1:10:19 PM9/4/15
to Aleks Totic, Polymer, al...@streak.com
On Fri, Sep 4, 2015 at 11:11 AM Aleks Totic <ato...@gmail.com> wrote:
1000 elements budget is stingy for single-page apps. Do hidden elements count against the budget?

Elements out of the render tree are less of an issue (no layout/style recalc) but they'll still run callbacks. I think the point is, we need to better expose the cost of using an element to developers (paint + layout + js + recalc style). Right now, the tools are not helpful.

FWIW, I did a quick survey of a few modern SPA on page load. Here are their element counts:

maps - 624
contacts - 713
inbox - 988
calendar - 968
photos - 1106
github - 1267
gplus - 2838
gmail - 2890

Ran: document.querySelectorAll("body /deep/ *").length

What's interesting is that the newer apps (esp. Inbox) create far less DOM on page load. They're being good citizens in that they load on-demand. If you start clicking around (opening threads, expanding cards, etc.) that count goes up. 
 

Polymer's coding style encourages using lots of elements ("there is a component for that"). 

Number of elements component uses is unknown to the developer, until you inspect the dom. Usually, it is surprisingly high (10 elements for paper button).

We've got several open bugs like these:
 
Even our own elements need perf work :)

Aleem Mawani

unread,
Sep 4, 2015, 1:13:16 PM9/4/15
to Eric Bidelman, Aleks Totic, Polymer
Are these sites that you mention using polymer? Are those polymer element counts or DOM element counts?

Eric Bidelman

unread,
Sep 4, 2015, 1:15:05 PM9/4/15
to Aleem Mawani, Aleks Totic, Polymer
On Fri, Sep 4, 2015 at 11:56 AM Aleem Mawani <al...@streak.com> wrote:

Thanks for the info. Here's a screenshot of my real ui (ci build server).

Screenshot 2015-09-04 09.39.25.png

On screen I'm only displaying 3 builds and that still results in 348 polymer elements and roughly 900 regular Dom elements being created at page load. Thats about 120 polymer elements for each of those builds. The performance is ok with just 3 builds.

Ideally my ui shows 50 of these builds in a scrolling list. It seems that even when using an iron list, it creates several extra items for buffering and the render delay then becomes noticeable.

It'll help manage the list of items for you. Generating 3-10 items is  better than the entire list :)

Can you explain a bit more what you meant by hiding list items behind a dom-if? Isn't that the point of the iron-list, that it won't create many list elements because it only creates enough to fill the viewport plus some buffer. How does the dom-if help?


Until the user opens the feature card, all of that DOM isn't stamped. Some of it's custom elements, some <span> and <div>s.  

Any ideas to reduce the rendering time in general?

Summary:

1) How does the dom-if help?

2) Ideas for reducing the number of items created or lowering the initial render time?

3) Any idea when that improvement to iron-icons will be released. We use a lot of icons :)

It's out now! bower update and start using it. I see a lot of icons
on your page so it'll definitely help your instance count go down. 

Aleem Mawani

unread,
Sep 4, 2015, 1:22:44 PM9/4/15
to Eric Bidelman, Aleks Totic, Polymer
On Fri, Sep 4, 2015 at 10:15 AM Eric Bidelman <ebi...@gmail.com> wrote:
On Fri, Sep 4, 2015 at 11:56 AM Aleem Mawani <al...@streak.com> wrote:

Thanks for the info. Here's a screenshot of my real ui (ci build server).

Screenshot 2015-09-04 09.39.25.png

On screen I'm only displaying 3 builds and that still results in 348 polymer elements and roughly 900 regular Dom elements being created at page load. Thats about 120 polymer elements for each of those builds. The performance is ok with just 3 builds.

Ideally my ui shows 50 of these builds in a scrolling list. It seems that even when using an iron list, it creates several extra items for buffering and the render delay then becomes noticeable.

It'll help manage the list of items for you. Generating 3-10 items is  better than the entire list :)
will try thanks. 

Can you explain a bit more what you meant by hiding list items behind a dom-if? Isn't that the point of the iron-list, that it won't create many list elements because it only creates enough to fill the viewport plus some buffer. How does the dom-if help?

ahh i see. This brings up an interesting question about how you maintain that open state when using an iron-list or dom-repeat as the data changes. I'll post a new question to the group.

Eric Bidelman

unread,
Sep 4, 2015, 1:23:47 PM9/4/15
to Aleem Mawani, Aleks Totic, Polymer
None of them are using Polymer. I was just pointing out that modern apps don't use 1000s of nodes. They load things responsibly, on-demand. This is something you should be doing with or without Polymer/web components.

FWIW, I agree that this is really hard. Custom elements are SO easy to use that we need to make sure developers are able to use them without worries like this. But it's also important to have these types of conversations so people understand the tradeoffs, design patterns, etc. Many people I talk to assume web components fix everything about web development. There are still dark paths! 

Eric Bidelman

unread,
Sep 4, 2015, 1:26:19 PM9/4/15
to Aleem Mawani, Aleks Totic, Polymer
Features are toggled by user gesture:

<div on-tap="_toggle">

The _toggle() method sets the .open property and the rest is taken care of by bindings.

Aleem Mawani

unread,
Sep 4, 2015, 1:32:04 PM9/4/15
to Eric Bidelman, Aleks Totic, Polymer
Its made more tough by not the fact that the number of elements inside of a webcomponent is unknown (until you try it and look for it).

For example each one of those build cards has 264 elements in it. Looking at the markup I wrote that seems way out of whack which basically means that most of the elements are coming from children of paper-button, paper-icon, etc. Optimizing the components themselves seems to be one path forward.

Aleks Totic

unread,
Sep 4, 2015, 11:46:51 PM9/4/15
to Polymer, ebi...@gmail.com, ato...@gmail.com, al...@streak.com
Removing  paper-tooltip import from your example cuts down your loading time to 2.2s from 5.5s. I suspect that dom traversal is costly.

Aleks

Arthur Evans

unread,
Sep 10, 2015, 2:41:22 PM9/10/15
to Aleks Totic, Polymer, Eric Bidelman, al...@streak.com
I wonder if wrapping each tooltip (and the control it's labeling) in a <span> instead of using the `for=` attribute would be more performant.

If the former is significantly faster, it would be worth documenting.



Reply all
Reply to author
Forward
0 new messages