vue icon indicating copy to clipboard operation
vue copied to clipboard

list rendering optimization fails in some cases

Open miquels opened this issue 8 years ago • 5 comments

I have virtual scrolling list with a lot of rows. I only show a few of them at a time using

this.view = this.items.splice(position, position + 5)

If 'position' is incremented or decremented, you would expect that in the DOM one element gets added, and one gets deleted. In the 'up' direction, that is the case. But in the down direction, all elements get removed and added again. I have a couple of images in each row, and this hurts performance quite a bit.

Vue.js version

2.1.3

Reproduction Link

https://jsbin.com/netereyuxa/1/edit?html,console,output

Steps to reproduce

press up / down, see that in the up direction one LI is removed and one added at each step, and in the down direction all LIs are replaced every time.

What is Expected?

Only one LI added, one LI removed

What is actually happening?

All LI's removed and added

miquels avatar Dec 02 '16 00:12 miquels

To be specific:

  1. the <li>s are being properly reused (i.e. not replaced by newly-created elements)
  2. there are indeed more "move" operations than necessary.

However, based on Chrome's timeline tracing, it seems both moving up and down has very similar rendering/painting costs. I wouldn't really consider this "failing", but maybe it can be improved. Are you experiencing visible slow down in your app? How complex is each item in your actual list?

yyx990803 avatar Dec 02 '16 02:12 yyx990803

On a reasonably modern laptop you can't see the difference. I think can see a slight difference on my Asus TF300T tablet, but that one is four years old.

The use case is a virtual scroller. It shows a couple of rows in the viewport, and when scrolling rows are inserted / deleted as they scroll into / out of view. Each row is a LI element, which contains 5 DIVS, each with an IMG (20K jpeg) and some text.

I was just trying to optimize the list rendering in my component, noticed this issue, and thought this was a small bug in the algorithm, that's why I reported it. If it's hard to fix correctly, or impossible to fix without some other performance impact, then please don't bother :)

Thanks for the quick reply!

Mike.

miquels avatar Dec 03 '16 20:12 miquels

I am also implementing a virtual scroll feature and I came across the exact same problem. Unfortunately the problem seems to hurt performance quite a lot when smooth scrolling, e.g. on a Macbook Pro with the touchpad. Scrolling upwards is buttery smooth, while scrolling downwards creates micro-stutter caused by the many dom updates. Here's a capture from #7477 that shows the problem very well (https://jsfiddle.net/1m5vx6dc/1/):

dom

mofux avatar Jan 18 '18 22:01 mofux

I just tested this with Vue 3 - with the example provided by mofux above. It looks like this is fixed now, so this issue can perhaps be closed.

ghost avatar Jan 31 '21 14:01 ghost

If you're using Vue version 2: I found a dirty fix that seems to work for me. I had a input control inside a list item that lost focus when the current list item moved down, but not up. This problem can be (kind of) avoided when adding a watch combined with a nextTick that checks if the control has lost focus. I don't know that this works 100% in every case, but this is how I fixed my issue:

items: {
    handler(newValue) {
        const focusedElement = document.activeElement;
        console.log(focusedElement);
        this.$nextTick(function () {
            if (document.activeElement !== focusedElement) {
                focusedElement.focus();
            }
        });
    },
    deep: true,
}

Here is an example: https://codepen.io/and3k5/pen/zYewLxN

and3k5 avatar Nov 10 '23 13:11 and3k5