binding: Slow DOM updates if using unshift on an array
I have a posts
property that is an array of post objects displayed on the page. I have navigation buttons on the page that will make an api request and add multiple posts to the array, either at the start or the end of the array depending on which way they are navigating:
// Insert results
if(page == 'prev') {
this.posts.unshift(...response.posts);
} else {
this.posts.push(...response.posts);
}
When Array.push()
is used it looks like the new appended objects get new appended elements in the DOM, this is really fast.
Alternatively when Array.unshift()
is used it seems new elements don’t get prepended, instead it looks like the current elements stay the same and any extra elements are appended to the DOM so the count of DOM elements match the array length. The properties for each object in the DOM are then updated to be in sync. This seems much slower.
This is causing issues as I have an array observer listening for updates on the posts
array. When it updates I need to check some stuff in the DOM. This works fine for Array.push()
but with Array.unshift()
rendering hasn’t finished so I get incorrect DOM results.
Example:
this.arrayObserver(this.posts).subscribe(() => {
this.taskQueue.queueMicroTask(() => /* DOM stuff here */);
});
This worked in older versions of Aurelia. It would appear this is some sort of performance improvement to try and reuse elements, however it’s definitely degrading performance in this use case.
Is there some sort of Aurelia event I can hook into that will fire when all Aurelia DOM stuff is finished for this array update? Or would I need to downgrade Aurelia to get this working again?
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Comments: 25 (15 by maintainers)
@niieani I just sent you a core team invitation. Pending your agreement to join, this seems like a great issue for you to start work on 😄
@lukechilds I see. As far as I know, there isn’t any event that fires after a repeat has finished re-rendering. I suppose your way is the closest to achieving that. However it would be trivial to add something like that to the
repeat
custom attribute to achieve the following:someMethod
from the view-model would fire every time the repeater finished updating all its views. Would something like that solve your case? @EisenbergEffect Do you think this is something worth implementing?@niieani Talk with @jdanyow and @martingust about that to see what they think.
@lukechilds Micro tasks are put on to a draining queue that runs as soon as possible, before rendering. Macro tasks (or just tasks) are executed after the next “paint” or as soon after that as the browser will allow.