I would like to create a scrollable list on a web page using jQuery. Each item in the list would contain an icon and some small amount of text (the typical size for user comments). I anticipate users scrolling up to a maximum of a hundred items, although some users could scroll a lot more.
There are two approaches I can think of. The first is where you just add one item for each row and all rows are in memory. Of course, this does mean that the DOM will use up more memory than the alternate approach.
The alternate approach is similar to the way mobile apps (Android in particular) manages lists. Instead of having the layout for each row in the list, you only have a small number of layouts, usually enough to fill the screen plus a few more. When the user scrolls down to expose a new row, the row at the top that disappears from the list would be reused for the one appearing at the bottom. In other words, you're reusing layouts to save on memory, although I'm not sure what impact performance will have. In Android, this is known as the RecyclerView.
Is there any benefit in creating a list that reuses layouts as opposed to just having all the layouts for all rows in the DOM? While this may be an issue for native mobile apps, I am not sure if it's an issue for web apps. Note: The web app will only be available for desktop browsers and not for mobile browsers.
Related
A particular page on our site loads with 1000s of divs each about 1000px x ~1500px(A printable page), each div displays additional elements/basic table/etc but can vary in height.
Render time can be several minutes depending on PC performance.
Using tools like webix which can load millions of rows proves the render process is taking up most of the loading time, but doesn't work well for non-tabular data.
Using Angular JS to create infinite scroll lists is possible. But this also doesn't work well with varying height elements.
All solutions I have found so far loose the browsers find feature, which our users commonly use, thus we will probably have to develop our own search tool.
Yes we could add pagination, or some sort of way of breaking down the data, but users still need to review all the data regardless of how it's broken down.
The same data (10,000 pages 30mb) once exported to PDF loads in < than 1 second.
I think the best solution will be the combination of a few different ideas.
Long stay made short, marketing wnats our entire sitemap (5000 pages) in one menu. After 1 year of fighting them on this, there is no winning and we must implement.
We are currently evaluating technologies that will help us make this decision.
Some menu items will have recursive nested levels 5 items deep(insane I know).
The data is driven from JSON because our sitemap is stored in XML in an archaic CMS (Ektron).
I am considering React but there may be no answer. We are looking for a JavaScript library that will help us achieve this and improve performance. Currently our menu alone takes 4 seconds to load for a desktop computer with a half decent Internet connection.
Question; Is using React for this a good idea? If not, are there any other options for us to consider.
Many thanks.
Take a look at React Infinite
When a long list of DOM elements are placed in a scrollable container,
all of them are kept in the DOM even when they are out the user's
view. This is highly inefficient, especially in cases when scrolling
lists can be tens or hundreds of thousands of items long. React
Infinite solves this by rendering only DOM nodes that the user is able
to see or might soon see. Other DOM nodes are clustered and rendered
as a single blank node.
Has anyone found a good way / module to enable zooming in on images in either the grid or list mode on the category view pages? I have a client who wants that, and also the ability to zoom in on the image for any featured products we place on the home page individually.
I know it's possible (by creating multiple zoom js instances, etc), but am wondering if this particular wheel has already been invented - my searching so far has not turned up anything, and I'm trying to keep the hours down here.
You need to do this yourself I'm afraid, using js libraries of course which is already doing most the work! As you already pointed out you need to create multiple zoom instances on the bits you want to have zoom. Really shouldn't take too long. Think about people with older browsers and machines though, creating lots of these instances on page (e.g. 50-100 product list) load may effect the performance of the site for some users and browsers. Maybe a hover over to initiate the zoom instance would alleviate this problem, or a simple hover over pop up instead of zoom.
Cocoa Touch's UITableView allows a user to scroll through large numbers of data rows with good performance because it recycles table rows. Rather than create a GUI element for every single data row, a limited number of table rows is created, and simply updated with the relevant data as the user scrolls, giving the illusion of navigating up and down a very large number of table rows.
Has anyone seen this done in javascript? Is there a plugin available anywhere that will do this for me?
infinity.js works well. It will dynamically load 'pages' behind the scenes giving you the appearance that the list has been fully loaded.
More information can be found on their Github page - https://github.com/airbnb/infinity
Additionally, I've forked the project updating it to work with Zepto. I also set it up to use any scrollable div (set up with overflow: scoll) with the class 'scrollable' - https://github.com/elliotcw/infinity
I should add that I made these changes as this is great for large lists on mobile devices, which slow down when you have to many complex elements on the page.
I was looking for this as well, and infinityjs [1] doesn't seem to quite mimic the same interface as UITableView. And it was a problem for my scenario that infinityjs required that the element containing the list items already be added to the DOM.
MegaList [2] came closest to what I wanted. Andrew (author) has done a great job of designing it for mobile first, with touch support etc. One caveat for me was that it appears to assume a strict selection list model and does a little bit more than I'd like a list component to do (e.g. binding to resize events and trying to handle that automatically).
So I started writing a barebones list component, also modeled after the iOS UITableView. It's a work in progress and I'm putting in just what I need. Sources are here https://github.com/shyam-habarakada/js-virtual-list-view. I'm putting in just what I need as I go, and contributors are needed :-)
[1] http://airbnb.github.io/infinity/
[3] https://github.com/triceam/MegaList
Actually the algorithm is not difficult at all. If you know javascript you should be able to write this. The algorithm only needs the height of a cell and the height of the table.
I only know these two:
Apple's Dashcode javascript Framework has an implementation of a Table. You could take a look and see if that is what you need.
Or Cappuccino Framework which is basically Objective-J but behind the scenes is Javascript.
Clusterize.js does exactly that.
It's small and works with any tag (table, lists, divs)
I really don't have any substantial code to show here, actually, that's kinda why I am writing: I looked at the SproutCore demo, especially the Collection demo, on http://demo.sproutcore.com/sample_controls/, and am amazed by its loading 200,000 records to the page so easily. I tried using Rails to provide 200,000 records and in a completely blank HTML page with
<% #projects.each do |p| %>
<%= p.title %>
<% end %>
that freezes the browser for seconds on my m1530 laptop with 4gb ram and t7700 256gb ssd.
Yet the sproutcore demo does not freeze and takes less than 3 seconds to load.
What do you think the one technique they are using to enable this is?
Thanks!
The technology that SproutCore uses to display and scroll smoothly through "infinite" lists of data has very little to do with where the data comes from and almost all to do with the integration of special SproutCore view classes, SC.CollectionView (the parent class of SC.ListView and SC.GridView) and SC.ScrollView; the collection of powerful client side datastore classes: SC.Store and SC.SparseArray; and the SproutCore runtime and controller architecture.
The fact is that you simply cannot render a list of several hundred thousand items in it and expect the browser not to grind to a halt. That is too many elements to insert into the DOM tree and that is why SC.CollectionView is optimized to only generate elements for the currently showing items in the list (ex. if only 20 items are visible out of 20 million, only 20 elements are in the DOM). It gets even better than that though, because by default as items scroll in and out of view, the few existing elements are updated in place with the new item information so that the DOM tree is not even touched. This would not be possible though without the integration of SC.ScrollView that allows the collection to be aware of its visible rect and when a scroll is about to happen.
On top of that, there is the entire SproutCore runtime architecture which is used to ensure that all DOM manipulations are queued up so that you only touch the DOM once per run loop if needed when a display property changes (ex. toggling a display property 50 times in one run loop only touches the DOM once with the final value). This is an important factor in extreme performance that affects all SproutCore views including SC.CollectionView.
Finally, to make the list really scream, you cannot load several million items into the client in one request, nor can you even store them all in client memory. This leads me to another optimization of SC.CollectionView and the SproutCore data store, which is to work with sparse data. SC.CollectionView will never try to iterate over every item in its content, so it doesn't need all the data present, only what is being shown. When we load data into the client, we would use an SC.SparseArray to page in a bit of data at a time as needed. The whole system is very elegantly designed so that when the collection view requests an item that the sparse array doesn't yet have, the sparse array fetches it (or the next page of items) in the background. Because of bindings and observers, when the new data comes in we can update the list in place, which means that the scrolling doesn't block while data is being brought in.
That demo above is very outdated, here is a new one that uses the technologies I mentioned above: http://showcase.sproutcore.com/#demos/Big%20Data (source is here: https://github.com/sproutcore/demos/tree/master/apps/big_data). In this demo, I scroll through 50,000 names, which is all I could generate and split into 500 JSON files of a 100 names each that are loaded remotely from the server. Once you scroll past 100 names, you will see that the next 100 names are paged in and there is a brief flash of placeholder text "…" (how long you see the placeholder text depends on your Internet connection).
I used 50,000 names, but I don't see any problem showing a list of 500,000 or 5 million names though. However, at that scale you would want to also 'un-page' data as you bring in new data using SC.Store#unloadRecords to keep the memory use down.
There's a few other technologies in play to make this whole thing possible that I've missed, but those are the main ones at least.
I imagine the demo provided isn't being generated dynamically - it's static data.
Very few systems would be able to iterate a collection of live data that size. There are a number of techniques including streaming the dataset (using batch iteration through the records) through to caching and ajax partial loading strategies.
More on sproutcore here.. http://ostatic.com/blog/sproutcore-raises-the-bar-for-client-side-programming
If on the other hand you are looking for concurrency then node.js is the way to go.