
Loading…
Performance: dom-repeat does not perform on large datasets #2537
I recognized the same issue when I used iron-collapse within dom-repeat for large datasets.
I ended up removing the iron-collapses as they performed terribly on toggling.
Anyway the large rendering block is really annoying.
for bringing this up.
It doesn't seem like there is any initial feedback so I am going to try and draft a PR to implement this optimization.
Don't you think it's a better approach to not add that amount of items to the DOM at all like <iron-list> does (virtual scrolling). What's the point of adding a lot of invisible items?
For my specific demo iron-list would work yes. However not all use cases of Dom-repeat merit the use of iron-list. It is specifically for those use cases in raising this issue
I didn't suggest to use iron-list, just to use virtual scrolling like iron-list does, instead of making DOM inserting more responsive.
We do plan to investigate adding a batched rendering mode to dom-repeat, to provide a middle solution between full-set blocking dom-repeat rendering and virtualized iron-list. Will keep this issue open to track.
@kevinpschaaf Would you like me to work on the PR or do you guys have a different direction you'd like to take it?
As mentioned, we are actively working on options for dom-repeat to allow an initial "critical section" render and chunk out the remaining items at rAF timing. This is in-progress, so I'd recommend waiting on that, but is very much along the lines you were headed.
Today we merged the incremental-rendering feature for dom-repeat via #2659 (will be included in next release).
Usage:
<template is="dom-repeat" items="{{items}}" initial-count="20">
...
</template>Setting initialCount will put dom-repeat in incremental rendering mode, with up to the initial count of items being rendered pre-paint, and all remaining items being rendered incrementally at requestAnimationFrame timing in chunks small enough to hit a best-effort framerate (default of 20fps, tunable via targetFramerate; higher numbers will improve event latency/throughput at the cost of longer overall rendering time).
@kevinpschaaf any perf demos / timeline dumps that we could look at?
@kevinpschaaf Thanks a bunch! I added the initial-count prop to the demo I mentioned earlier (http://jshcrowthe.github.io/dom-repeat-perf/non-chunked.html) and things are looking good!
I'm excited to put this to work with the next release!
@kevinpschaaf. I pulled your chunking feature branch a couple of weeks back. We was also suffering on perf with our app on large datasets, This seemed to work quite nicely. When released would you recommend keeping targetFrameRate at the default. Thanks for the update and also looking forward to this awesomeness
@dChin84 The question of targetFramerate comes down to a fundamental tradeoff that's hard to make for every app. A higher targetFramerate means the items will be fully rendered out more slowly. If it's more important that the users can quickly scroll and see all items, a lower target framerate may be appropriate. If users will immediately need to act on e.g. a slider (that requires high-frequency event handling) or kick off a requestAnimationFrame animation, a higher target framerate may be appropriate. 20fps seemed to be a good sweet spot in terms of giving repeaters more time to get their work done while sill being responsive to e.g. taps and some moderate high-frequency event handling.
Would be happy to hear from others experience on what a good targetFramerate ends up being for their app.
Thanks @kevinpschaaf, I'm really impressed! My performance problems with large datasets are gone, only by adding an initialCount. A targetFramerate of 20 works fine for me.

When using dom-repeat with large datasets the browser becomes unresponsive for a period of time while the render task is being completed. The
<iron-list>component I believe was designed to solve this. However there are use cases that<iron-list>does not support (a grid view until that is implemented, or any other UI where repeated item position is calculated/randomized, etc).I have thrown together a demo on github (was going to do a fiddle but the dummy api I am calling causes the request to throw a
NET::ERR_CERT_COMMON_NAME_INVALIDerror)http://jshcrowthe.github.io/dom-repeat-perf/non-chunked.html
In the following timeline you can see that there is an long, event-loop blocking, render task that takes place immediately after the request completes
NOTE: My machine is a 2013 MacBook Pro 2.3 GHz i7 with 16 GB RAM
If you repeatedly click on the counter button while the request is being made you will notice that, up until the XHR request completes, the UI is responsive. However once the render task for the
dom-repeatbegins the subsequent click events are queued up and are unable to process until the full render has completed.I hacked around with chunking the rendering task (utilizing
setTimeout(function() {...}, 0)) and was able to create a functional proof of concept that illustrates a potential solution. A demo can be found at the following URL:http://jshcrowthe.github.io/dom-repeat-perf/chunked.html
Before I go too much further with this I wanted to get feedback to see if this was a good potential solution or if I am altogether going about this wrong. You can see the actual change I made here:
jshcrowthe/polymer@a5d5edd
NOTE: I have only modified the
_applyFullRefreshrender method for the sake of demo. If this is a good solution all 3 of the render types would probably want to have this type of logic. In addition to that a way to abort an "in progress" render would need to be implemented to ensure that multiple calls to_applyFullRefreshdon't result in duplication. You could also implement this type of chunking with DOM removals if it proves to be similarly slow.If you compare the timeline for the chunked render you can see a drastic change in the timeline. The UI is not rendered all at one time however the render task never takes so long (at least in this simple instance) where it blocks user interaction.