I have an Angular4 app with an endless list, using ngx-infinite-scroll:0.5.1. I am also using lazy loading for each section of the website.
When I first enter the section with the large infinite-scroll-list, the performance is quite good, the scroll events are very responsive and everything feels quite smooth. I can then scroll to the end of the list (1000 component items), loading and attaching further chunks to the list, like so:
addToTileListData(tileDataList: any) {
// Build temp list
let tempTileDataList: List<PxTile> = List<PxTile>();
for (let tileData of tileDataList.body) {
const tile: PxTile = tileData as PxTile;
tempTileDataList = tempTileDataList.set(tempTileDataList.size, tile);
}
// Merge temp list with visible data
const newList = <List<PxTile>>this.tileList.concat(tempTileDataList);
this.setTileList(newList);
}
The 1000 components are immutable.js items using ChangeDetectionStrategy.OnPush
When I leave the section and enter another lazy loading section, the previous section with the large list is destroyed.
But when I then navigate back again to the section with the large infinite list, the list quickly becomes very sluggish while scrolling, up to the point that, when I scroll to the end of the list of 1000 items, the scrolling almost freezes.
Do you have any suggestions what the problem could be? Or how I should proceed? Does this problem sound like a memory leak?
If I check the performance tab of the Chrome developer tool I can see that at the same time, dozends of scoll events stack on top of eachother:
Thanks a bunch for your help!
Related
I am wondering what would be a stable algorithm that can determine a length of a scrollable carousel.
For example i have a view with left andright button that can go through the whole collection of items.
The items can be repetitive and non-unique. For example :
A<->B<->C<-D->A<->B<->C<->H<->G ( G is connected to A with <->)
Using a bot that can inspect the state and click,
how many times i need to go through the whole list to determine that is the final one ?
thanks
It's my first question here, and i'm not an english native speaker, so i apologize in advance, if that makes my explainations difficult to understand.
CONTEXT
I'm in charge of the developpement of a small application which manipulate vocabulary sets.
The application is built on GWT, added by GWT-Bootstrap and some other libraries, that have nothing to do with the ui part of the application.
To expose to the user the terms of this vocabulary, i use a tree stucture, visually speaking.
STORY
The tree has few requirements, it has to allow drag&drop features for his items and show connectors between them.
I started by using the Tree ui class from the native GWT components. It turned out that with a lot of terms loaded in the tree, the performances felt down, even in production mode.
I decided so to try the CellTree implementation, but it didn't fit for me since make disappear the "showmore" button is not an easy task, and styling the tree too.
I finally ends up with my own implementation of a tree, from scratch.
This implementation relies essentially on a simple html list structure (ul-li), and benefits at maximum of css capabilities. Indeed, expanding a tree node is done with css, using a trick known as "checkbox hack".
At this point the custom implementation of the tree is fast (better than tree or celltree), even populated with thousands items, and it met the requirements, but...
THE ISSUE
When an item is being dragged over other items, the style of those items change depending on dropping possibilities.
1st Solution
The first idea was to benefit of the css, and use the :hover selector to change the style of the items, depending on their classes.
But there is a major issue in current browsers (specifically Chrome), which make the css :hover not triggered, if the mouse left button is down, which it's the case when you drag something (chromium issue 122746)
It seems that i have to forgot an exculsive css solution, until the :hover triggering issue will be closed.
2nd solution
The only other solution to which i came by is to change the style of the item programmatically.
Code of the handler
#Override
public void onDragEnter(DragEnterEvent event)
{
if (event.getSource() instanceof Word)
{
event.stopPropagation();
event.preventDefault();
Word word = (Word) event.getSource();
word.addStyleDependentName("over");
}
}
#Override
public void onDragLeave(DragLeaveEvent event)
{
if (event.getSource() instanceof Word)
{
event.stopPropagation();
event.preventDefault();
Word word = (Word) event.getSource();
word.removeStyleDependentName("over");
}
}
It works fine with a few items, but when dealing with thousands it make the application freezing, and the rendering is somehow random.
PRECISIONS
The issue appears when dealing with 5000 items in the tree (the application must handle such dataset).
I'm aware of efficient events handling concerns, as event bubbling, and the handler is unique as it is recommanded when the number of potential handlers, if made specific for each item, is a factor of lack of performance as the number of items increase.
Secondary i've used the speed tracer to analyse the source of the problem, and it turned out something i don't understand:
Events are incredibly slow on top elements of the tree, specifically the paint event which take 1 second to be fired after the style recalculation
Slow events Speed Tracer Screenshot
Events speed is fair enougth on bottom elements of the tree
Fair enougth speed events Speed Tracer Screenshot
QUESTION
I'm stuck with this issue since few days, and i wonder if someone could point out what i am missing.
Perhaps, the behaviour is totally normal, but maybe there is a workaround for a such issue ?
I'll be glad if someone could help me on this point.
Thanks you for any reply !
lilBrain
If you are using GWT-Dnd please have a look at that;
Slow drag performance when there are a lot of draggables on screen
It's mentioned that this performance issue is related to finding x, y coordinates of the widget on a drop event.
com.allen_sauer.gwt.dnd.client.DropControllerCollection.getIntersectDropController(int x, int y)
there is a block of code that loops through the DropController candidates with what appears it's only purpose being for debugging.
for (int i = sortedCandidates.length - 1; i >= 0; i--) {
Candidate candidate = sortedCandidates[i];
if (DOMUtil.DEBUG) {
DOMUtil.debugWidgetWithColor(candidate.getDropTarget(), "blue");
}
}
subsequent to that, the code then loops through and actually tries to
identify if the x and y coordinates are over a DropController.
Hope this will help you.
I've have found some weirdness with Maps V3 in jQuery UI tabs.
A common issue, when a map is initialized in a hidden tab, it gets confused and doesn't know how big to make the map.
The solution for this is:
$('#tabs').tabs({show: function(e, ui) {if (ui.index == 5) {google.maps.event.trigger(map, "resize"); } }});
That works fine. That maps resizes visually in the tab.
The next issue, perhaps less commonly, is that I want to load markers based on the latLng of my site's users. When I try to load them via the init function, the getBounds appear to be the same... I assume it's the same issue. The map is confused about the load size.
Like the trigger for resize, is there a way to trigger a function and pass the map DOM info after it has been initialized? I am so new to this!
what does Recalculate Layout Paint mean in chrome developer tool TimeLine records? and how to improve the page performance by reduce the page Recalculate,Layout and Paint's count? can give some suggestion?thanks
Basically, they're your browser figuring out how to draw the changes that you made to the page.
Don't worry about getting rid of them -- if you did that, your site would be static.
However... ...if you want to do something that IS useful for performance, which does have to do with reflows and repaints, then batch your changes together.
Lets say that you got a job at Twitter.
And your job is to write the next version of the window that adds each twitter post to the screen.
If a user gets 250 new tweets in their timeline, and you add each one in a loop, one after the other, the browser is going to slow way down, because every time you add one, it will have to reflow (move things around to make space for the thing you added) and repaint (style everything that was affected by the addition).
A better way of doing it would be to build the list of new tweets together off-DOM (ie: with elements that aren't actually on the page right now), and then add them all at once.
This cuts down on the number of times that a browser has to figure out where everything needs to go.
#Fabricio -- Micro-optimizing might not be great, but appending hundreds of browser elements in a loop, versus putting all of them in at the same time can make a big difference.
Just ask the Twitter guys, who weren't bothering to cache their jQuery objects.
Here's a very handy list of properties and methods that trigger the layout (reflow) of a page:
http://gent.ilcore.com/2011/03/how-not-to-trigger-layout-in-webkit.html
You want to minimize these calls as much as possible -- especially in situations where performance is critical, such as during the scroll event, or when animating large blocks of content.
You can use the "Profiles" tab and "Audits" tab to detect the performance of your code. The will give you a report about your codes.
You can reduce the page Recalculate,Layout and Paint's count by many ways.
Append many child at one time.
Hide elements before change them.
Give images and other elements height and width.
I'm writing a simple dictionary app which gives suggestions for words as you type. The suggestions are displayed in a ListBox and each time the query changes, about 10 suggestions should appear.
Unfortunately, performance is low at the moment. It takes almost a second for the results to appear and I don't understand why. EQATEC Profiler shows that my methods are running smoothly. I've confirmed this by putting a Stopwatch around my code. I've also experimented with the number of suggestions, and performance does increase with fewer items.
This leads me to conclude that rendering the ListBox (which I presume happens outside of my methods) is to blame for the lack of performance.
Does rendering 10 items in a ListBox really take more than 250ms?
How can I quickly put a small number of words on the screen?
Edit:
The way I fill my ListBox is very straightforward. Is it the right way?
resultsListBox.Items.Clear();
foreach (string s in suggestions.Words)
{
resultsListBox.Items.Add(s);
}
resultsListBox.SelectedIndex = suggestions.MatchIndex;
What you see here is really it: default ListBox, String items, no templates. Do I violate one of these principals?
Ensure you have the item data template in a fixed sized container (grid).
Avoid/remove using complex converters, when the same information can be easily provided by the data object.
Avoid/remove nested structures, example listbox in a listbox item.
Strongly recommended to not use user control inside the data template.
Avoid/remove custom controls from the data template
The link below contains a demonstration of the ListBox performance in a simple project.
The project also shows an alternative (faster) way to display a list, using a Grid with Buttons. This list is not scrollable and therefore not a real solution.
http://www.mediafire.com/?jypcfm4cs3nvo5c
Remember to run the project on a device, because the emulator has very different performance. I've tested it on the Samsung Omnia 7.
It sounds like you're creating your own AutoCompleteBox. Is there a specific reason for not using the one in the Toolkit?
I would expect the time taken to update the listbox to be dependent upon: how you're updating it; the complexity of the listbox; and whatever-else is on the page.
In that you haven't provided details about any of these it could be possible that it will take this long.
Edit
As an alternative to the AutoCompleteBox (In theory you shouldn't need to scroll the results of this--just enter more characters to filter further.) I've done some experimentation and the following seems to work best. It uses a StackPanel inside a ScrollViewer and reuses the existing items, rather than creating new ones.
<ScrollViewer Height="629" Margin="0,139,0,0" Width="480">
<StackPanel Name="listBox1" />
</ScrollViewer>
cs:
private void InitializeResultsGrid()
{
...
for (int i = 0; i < 26; i++)
{
...
listBox1.Children.Add(new TextBlock());
and
private void SlowFill(string baseStr)
{
for (int i = 0; i < buttons.Count; i++)
{
(listBox1.Children[i] as TextBlock).Text = baseStr + (char)(i + 'a');
}
When I timed it, it was slightly slower than using the Grid but the performace seemed fine to me on an LG-E900