With the release of the new Ext JS 4.2 Beta, we’ve made a host of changes. You can read the full details in the forum announcement. In this article, we will highlight the improved performance of our Grid component.
In previous posts on Ext JS 4.1 Performance and Optimizing Ext JS 4.1-based Applications, we highlighted the improved buffering capabilities for the Grid component. Ext JS 4.2 further enhances the performance of buffered rendering and allows this feature to be used in more situations with much less configuration. Applications featuring large data sets should see a dramatic increase in responsiveness thanks to these optimizations.
Table of Contents
Comparing the Grid in Ext JS 4.1 and 4.2
In Ext JS 4.1, the Grid component physically re-rendered the table of rows every time the user scrolled into the buffer zones. For example, imagine a grid that rendered 50 rows at a time. If this grid currently displayed rows 100-150 and the user scrolled down to record 105, the grid would re-render the table of rows to display records 105–155.


The Grid component in Ext JS 4.2 changes the way rows in the display table are managed. Using the previous example, the 4.2 Grid will remove rows 100–104 (no longer visible) and add rows 151-155 as new elements. This optimization results in a significant decrease in rendering latency and subsequent increase in performance.
The performance test we put together was an automated scroll down a 2000 row grid. The total time spent scrolling from top to bottom in the 2000 rows was measured on IE8 (on Windows XP using a 1.8GHz CoreDuo Thinkpad with 1GB RAM). The improvements in Ext JS 4.2 have resulted in a 2x (or better) reduction in latency — which should equate to much smoother, fluid scrolling.
Ext.grid.plugin.BufferedRenderer
To access buffered rendering for a Grid in Ext JS 4.1, we had to manually define a data store with a “buffered” config in order for it to interact with the paging scroller. That meant a store might be defined as:
// Ext JS 4.1 style buffering on the store var store = Ext.create('Ext.data.Store', { // allow the grid to interact with the paging scroller by buffering buffered: true, pageSize: 50, data: dataJson, model: 'Employee', proxy: { type: 'memory' } }); var grid = Ext.create('Ext.grid.Panel', { store: store, loadMask: true, //etc... });
While the “buffered” config was a convenient way to optimize the performance of our data stores, it also meant that the store was acutely aware of how its data was to be displayed. As some components might share a data store, defining the buffering feature on the store-level could be problematic.
Additionally, buffered stores in Ext JS 4.1 encountered problems as users edited the records in the grid. Because only the rendered rows existed in the store’s main record collection (unrendered records would be hidden in a private page map), editing records and syncing data became challenging.
Ext JS 4.2 solves this issue by introducing the Ext.grid.plugin.BufferedRenderer
plugin. This plugin allows the store to remain ignorant of its display — the Grid component is now solely responsible for buffering the display of its associated data.
// new Ext JS 4.2 Ext.grid.plugin.BufferedRenderer Ext.require([ 'Ext.grid.plugin.BufferedRenderer' ]); var store = Ext.create('Ext.data.Store', { pageSize: 50, data: dataJson, model: 'Employee', proxy: { type: 'memory' } }); var grid = Ext.create('Ext.grid.Panel', { store: store, loadMask: true, plugins: 'bufferedrenderer', //etc... });
This grid will render a partial table — the same way as it did in Ext JS 4.1.x — but it removes the added configurations for the data store. This also means that all grid/store features (e.g. grouping and editing) will work seamlessly with this plugin. And because the buffering functionality is no longer defined on the store, normal store functionality (edit/save/sync) can all be enabled at the same time on a buffered grid.
Having said that, the buffered store (seen in the first example, above) still exists in Ext JS 4.2. Buffered data sets are still important to many real-world applications — the new Buffered Grid plugin is simply an alternative implementation with additional performance enhancements specific to the Grid component.
Configuration
The BufferedRenderer plugin can easily be configured to control the number of rows rendered outside the visible area, as well as the number of pages of data to buffer from the data source (remote or local).
The “trailingBufferZone” and “leadingBufferZone” configs operate in the same way they did in Ext JS 4.1.x — but these configs now live on the plugin rather than the store. (As noted earlier, the buffered store still exists — so for unbuffered stores, be sure the plugin is configured with these values.) You can tell it to create a larger table to provide more scrolling before a refresh is needed, and also to keep more pages of records in memory for faster refreshing when scrolling.
The BufferedRenderer plugin can also be configured with a “variableRowHeight” property in case where the data may have unpredictable sizes (cases that may involve custom cell renderers or text wrapping). This config defaults to false
in order to optimize the grid’s performance. (Note: certain features like “grouping” and the row expander will set this flag for you.)
Dig Into the Ext JS 4.2 Examples
To see the BufferedRenderer plugin in action, download the new Ext JS 4.2.0 SDK and open the examples to start exploring some of the Grid samples (located in the /examples/grid/ folder).
- Infinite Scrolling Grid (infinite-scroll.js)
- Infinite Scrolling Tuner (infinite-scroll-grid-tuner.js)
- Buffered Scrolling (buffer-grid.js)
- Variable Height Rows (var-height-rows.js)
We hope this performance enhancement to the Grid is a useful addition to your applications.
The problem with mzpivotgrid is that the data type is the same all the way down a column, except in special summary rows. What I’d like to see is a standard grid, flipped around its leading diagonal, which would be useful for things like comparing different product models, presenting one model per column.
Have a look at this post in regards to Pivot Grid:
https://www.sencha.com/blog/mzpivotgrid-a-pivot-table-for-ext-js
Forum post:
https://www.sencha.com/forum/showthread.php?237492
I’m also hoping for a pivot grid, by which I mean a grid in which one can configure a different data type for each row, and the arbitrary number of columns are populated from a data store.
Can you please make Sencha grid Responsive, So it will work on mobile devices.
Awesome, can’t wait to try this. Having to define buffering on the store (in 4.1) led me to have to define multiple stores with the same endpoints to avoid collisions in components which more or less shared the same data. Would love to drop the unnecessary workarounds. Looking forward to this!
Any improvements to charts?
Sounds great !!
What about pivot grids, Is it going to be the part of version 4.2 ?
What about RTL?
good wish to serial products sencha.
The main and most important features are still missing- which makes EXT very difficult to use for “real” Web based apps that go beyond the scope of the examples.
And what features would those be Jonas? Would be in terested to know. We are managing to use ExtJS to build “real” apps – including features that go far beyond the scope of examples.
So where is the demo? Please make 4.2 beta available online to provide a first look.
The RTL demo is broken in the examples.
@hitman001 – There should be some more information coming soon about charts. You might try downloading the beta to see what’s in there ;-)
@Bharat – I don’t believe the pivot grid has been added yet, at least not in this beta release.
@Jonas Halor – Can you be more specific? I would disagree, but we would love to hear what suggestions you have.
@Alfa1 – Just download the ZIP. Demos are included, but nothing is hosted yet (to my knowledge). It’s still in beta so we may hold off until the stable release.
@fafche and @Bostjan Rihter – I think the engineers are aware, but I’ll mention it. This is the first beta, so we’ll have that working by the full release.
“normal store functionality (edit/save/sync) can all be enabled at the same time on a buffered grid”
Does this mean we can now add, remove, sort and filter on the full set of data, not just the rendered/paged data?
I had given up on upgrading to 4+ for a while so I’m not in the loop anymore…
I was told RowExpander-like functionality would be integrated into grids. Has that happened yet? If not, any prediction as to when it might?
@Sidereal Engine
For the common case, a normal (non-buffered) store has all the normal store features: filtering, sorting, grouping. Using the bufferedrenderer plugin, the grid only renders the necessary rows. All grid and store features should work.
The buffered store is still an option for massive data sets. Since these are never expected to be fully loaded by the client, features like filtering, sorting and grouping must be handled by the server. The use of a buffered store automatically activates the bufferedrenderer plugin.
@Jack –
Yes, this has been in the product since 4.0 – check out http://docs.sencha.com/ext-js/4-1/#!/example/grid/grid-plugins.html :)
I have added horizontal RTL buffering for the grids in 4.1.3….
@Arthur can you give out a roadmap for the grid buffering? I’ve been making modifications to the NodeStore, TreeStore, Lockable, Store and GridPanel. There were a significant changes made to get buffered (vertical+horizontal), locked tree grids to get working and I’m getting a bit frustrated each time there’s an upgrade.
Are you guys planning on an X-Y buffering anytime soon? I think TableChunking will be needed for horizontal buffering — it just needed to be 4 tables at a timet to have overlap in both XY directions.
It’s nice to see that the design that was hijacking the store for a view concern have been fixed. I’m wondering if this is going to fix the issue of not be able to sort and filter locally, when we know that we have all the data loaded ,all locally, in the browser. In the 4.1 release, it’s not possible to have lazy rendering and still do local filtering, and sorting, which was also a silly design flaw. If the lazy rendering is not picky anymore, it should always be the default.
This might be a wrong place to ask but will 4.2 chart have the option for multi series stacked chart? Something like this www [dot] people [dot] stfx [dot] ca/bliengme/ExcelTips/Columns.htm
Thanks.
@Jeffrey
I can appreciate the challenge there – if you need low-level features like that you will need to dig in deeply to the grid internals. Sadly that puts you in a hard way when we improve the component or add some of these missing features on our side. I don’t see a way to avoid such conflicts when making those kinds of deep changes on both sides.
That said, in an ideal world, the component has all the features you need and you don’t need to dig in so deep… it looks like we have addressed many of the needs you listed in 4.2: locked tree-grid and buffered tree rendering (coming in the next refresh). We have experimented with horizontal buffered rendering, but have not had time to settle on and implement a solution. Your suggestion is one of the front-runners by the way. :)
@Sebastien Tardif
We may make it the default, but that would potentially break code that assumed things were in the DOM that would now come and go. To your main point – yes, the concerns are now separated and the store can do whatever it needs to do while the view manages its own issues. This was a bit of a challenge for grouping due to collapsed groups but it should be there.
Nice one!
In 4.1 I got around the issues with store syncing on buffered grid by calling Ext.Ajax.request directly :
Love the Kitchen Sink demo, the Neptune theme is looking good!
I noticed http://ext.ensible.com/ Calendar is now a part of the demos, but couldn’t look it up in the API. I’m rather curious as to whether Extensible will now be part of Sencha? I haven’t talked to Brian in years it feels.
I translated it into Japanese.
http://www.xenophy.com/extjsblog/5075
Provision: Japan Sencha User Group
http://www.meetup.com/Japan-Sencha-User-Group/about/
Could someone from Secha dev please clarify if adding rows into the buffering grid is supposed to work? There was a forum question on this that was never answered: https://www.sencha.com/forum/showthread.php?232509-buffered-Grid-and-add-Data-dynamically
I have tried it now with 4.2.0 and it does not work at all. Rows are not added to the grid.
Looks like buffered grid is useless unless all rows are pre-populated during grid creation. Correct?
Try to change buffer-grid.js as in below.
Thanks
var store = Ext.create(‘Ext.data.Store’, {
……..
data: [],
//data: createFakeData(5000),
……..
});
“store.add(createFakeData(5000))”
“I noticed http://ext.ensible.com/ Calendar is now a part of the demos, but couldn’t look it up in the API.” The calendar example has existed in Ext since the 3.3 (or so) days, and was ported to 4.x in 4.0.1 IIRC. Nothing has changed. The example is a version of the Extensible calendar that was forked back in 2010, and is only an example. Extensible is still totally separate and still supporting Calendar Pro, which is fully maintained and has many more features (including recurrence support as of 1.6) and examples.
@Ilya Goberman –
For specific discussions like this, the forums are the place to go. The thread you mentioned was trying to edit a buffered store and that was not and still is not really supported. A buffered store is best thought of as a very large, partially available result set. In 4.2, the buffered rendering of the grid is independent of the store (buffered or normal), so you can use a normal store and perform edit operations.
@Don Griffin
Don, thank for your reply. I would like to ask your advice, if I may, as it is directly related to the Grid performance and this post.
I am currently converting a fairly large YUI project to ExtJS. There are some grid windows that display trader’s positions. The number of rows can be large (thousands) and as new positions get created, server sends messages to the client, and new grid row(s) get created asynchronously via store.add(). This functionality worked OK in YUI DataTable, but with ExtJS grid (not buffered) performance is horrible: trying to open grid with 3,000 rows and dozen columns freezes Chrome.
So I was excited after reading this post hoping that buffered grid would help me, but it looks like it will not be the case because I cannot modify store (?). Or perhaps I do not understand you because you say “edit a buffered store still is not really supported” and later “you can use a normal store and perform edit operations”.
What would you recommend in this business scenario for me? Or maybe ExtJS grid is not suitable for this type of application at all?
Thanks for your time.
@Ilya Goberman –
By “edit” I mean “make changes client-side that need to be saved to the server”. In this case you are not really editing so much as pulling in updates from the server asynchronously. If I follow you correctly… you are not making changes client-side, just reflecting server-side changes on the client’s cached copy. I can see two basic approaches that should work alongside the buffered rendering of the grid (which is obviously essential here).
The key here is getting the first amount brought over and rendered as quickly as possible. If the total number of records is too large to hold in memory then you need to use a buffered store. In this case, however, the only issue with a few thousand records is likely to be transfer and load time. So if you bring over a reasonable amount in one go and add that to the store that should get the ball rolling. Then proceed to read the rest in reasonable sized chunks to avoid large pauses as you decode and add each chunk of records to the store. You can keep the store up to date with the server-side changes like this as well.
This is very similar to what the buffered store will do for you. It will request pages of records from the server. The only limitation is that as-is, a buffered store will not reload pages when they are present in its cache. If you are using a buffered store, the process of keeping it up to date with the server is quite different. It will involve access the page cache which is an internal aspect of the buffered store. But it sounds much closer to what you are trying to accomplish. I would recommend discussing this in the forum and see about getting a feature request created to more directly support this scenario.
If you read the posts above, you will see that other users have extended the reach of the core components to solve their specific use cases even though the component may not support that 100% out of the box. While this does present upgrade challenges, it can not always be avoided. Which is why I recommend opening a feature request as you progress towards solving for your specific use case… That and try to maintain such code in an area you know to check when you upgrade.
In my pre-Sencha life as a user of Ext JS, we maintained any overrides or patches to the framework in a separate location from the main body of our application to help us reconsider those items when we next upgraded. It was also a key advantage that the framework source was provided so that we could always solve our issues even if we had to resort to changing that code (always a last resort of course).
Even if you don’t have to modify the framework code, it is a good idea to read through the sections most relevant to you to better understand what is going on under the covers. In this case, I would look at how the page cache is managed by the store to see how you might be interact with or mimic that functionality.
Is the entire dataset accessible when using a buffered store plugin now. I am running into problems when trying to delete records that are not in the immediate record collection. I’m trying to implement a check-all box as a column header in a grid but it only knows to select those records which have been loaded into the store.
@Don Griffin
Tried to post couple times, but my posts did not get posted. Go figure. Trying again…
Don, it will not be a problem to populate the whole store upfront when the application starts up, so there is no need to have a buffered store. So I will have a store with one large single page and a grid with ‘bufferedrenderer’ plugin.
I would call store.add/ store.remove when an update from the server arrives. These currently do not work properly: grid gets updated, but once I resize it, all updates are gone.I believe there is a bug somewhere in the BufferedRenderer (just filed a bug report).
I would think that it would be in the Sencha’s best interest to fix it. The number of applications with this type of functionality will only continue to grow. ‘BufferedRenderer’ is still in beta – do you think it is possible to fix it before 4.2 is released?
Thanks
@Ilya Goberman
We certainly want to fix such problems. Where did you log the ticket? The forum or support?
@Vasu Gazula
Some confusion of terms there. There is no “buffered store plugin”. A store can be buffered with the “buffered: true” config. That is the same as before and doing this triggers buffered rendering (same as before). What is new is that a normal store (one without “buffered: true”) can be used on a grid with the bufferedrenderer grid plugin to get the same performance improvement.
When using a normal store, all of the content is loaded. This is not the case with a buffered store: it loads pages on demand (as it did previously). So unless you need the massive data set support of the buffered store, you can use a normal store and have direct access and control over the store content.
@Don Griffin
Don, the link is below. I really appreciate your help. I can provide any assistance testing it. This is a very important feature.
https://www.sencha.com/forum/showthread.php?251834-New-BufferedRenderer-Grid-plugin-does-not-work-properly-when-editing-store.
Thanks
By the way there is something seriously wrong with with the way blog comments/ bug reports are posted.
1) I have to log out for the blog comments to register. If I logged in, in they just get lost without any warning.
2) Just looked at the https://www.sencha.com/forum/showthread.php?251834-New-BufferedRenderer-Grid-plugin-does-not-work-properly-when-editing-store. All text is gone! It was perfectly fine yesterday. The only thing I did was editing it a little bit yesterday.
That’s a nice improvement for Grid
Just patched my code for 4.1.1a and looking forward for the new bugs and new patches for the 4.2 Grid :)
Is 4.2.0 Sprint 3 available for download somewhere? I would like to test it…
Problem with searchfield component
Uncaught TypeError: Cannot call method ‘substring’ of undefined ext-all.js:18
I sure wish the grid (as well as DataView and Form) in 4.2 would have support for to-one relationships out of the box.
We currently have to use a lot of workarounds to get this functionality with 4.1 and since to-one relationships are supported, it makes sense that the components (such as the grid) natively support it.
Just my 2 cents.
I love the changes to the grid though, keep up the great work!
All it would really need to support is using a nested property name for the dataIndex. So instead of just “name” it would allow “user.name” to pull in the “name” field/property of whatever sits in the “user” field/property of the current row’s record.
Sounds Good….
What about neptune support for IE8+9 and Firefox?
Pivotgrid, pivotgrid, pivotgrid pleaseeeeeeeeeeeeeeeeeeeeeeee !!!!!!!!!!!!!
Can anyone help me with pivot grid in extjs 4.2. When will sencha come up with pivot grid…is there anyone who has an example or working sample that i can use.