PolymerElements / iron-list

Element for a virtual, "infinite" list
https://www.webcomponents.org/element/PolymerElements/iron-list
217 stars 131 forks source link

Allow users to specify manual heights of items for performance purposes #331

Open danbeam opened 7 years ago

danbeam commented 7 years ago

Description

Scroll an <iron-list> full of complex items.

Expected outcome

Buttery smooth, 60 fps scrolling.

Actual outcome

Sometimes frames are super long. On bad Windows laptops we've seen ~250ms frames. With a bunch of text being ellided, or a box shadow being clipped (complex UI), we've seen a ton of style recalcs on measuring items via offsetHeight.

Additionally, if scrollTarget is used, accessing scrollTop or scrollHeight a bunch can also be slow (depends on the DOM tree in the target).

Live Demo

History page (chrome://history) on Chrome Canary.

Steps to reproduce

Visit crashsafari.com (note: don't do this for long), then open Chrome's history page on Chrome canary.

More Info

@blasten and I have debugged this and it boils down to: touching properties that trigger flushing in complex UIs can be slow. Even on my beefy Linux box.

So he prototyped an API that lets code cache or respond with hardcoded sizes. This was originally in the form of an item-height="itemHeightCallback" and something like:

Polymer({
  is: 'city-skyline',

  properties: {
    /** @type {!Array<!Building>} */
    buildings: function() { return []; },
  },

  /**
   * @param {!Building} building
   * @return {number}
   */
  buildingHeight: function(building) {
    return building.type == SKY_SCRAPER ? 200 : 100;
  },
});
<city-skyline>
  <iron-list items="buildings" item-height="buildingHeight">
    <template><!-- Building-y stuff! --></template>
  </iron-list>
</city-skyline>

Browsers Affected

(but probably others)

danbeam commented 7 years ago

Note that there are commits that address this in https://github.com/PolymerElements/iron-list/pull/316

danbeam commented 7 years ago

Additionally, it may make sense for any deferred work to pause itself if new input is discovered or it runs out of time. I know we've recently made use of requestIdleCallback but am not sure that we yet use the timer object passed to the callback as an argument.

blasten commented 7 years ago

@danbeam do you need this to launch History? There's also: https://github.com/PolymerElements/iron-scroll-target-behavior/tree/scroll-perf which is essential.

keanulee commented 7 years ago

@danbeam Is this still an issue for you?

danbeam commented 7 years ago

@keanulee this is a potential enhancement, yes, but hasn't been outrageously necessary.

We ended up finding out that our test case was for super duper slow items to render (long text clipped by text-overflow: ellipsis, which is like N^3 in runtime complexity).

I'd leave this as a low-prio enhancement and I'll update the title to more correctly indicate the spirit of this issue.

blasten commented 7 years ago

N^3?? 😳 Is there a crbug around that?