As
part of our Contract Management solution Contract Guardian, we have developed a reporting tool to enable us to
enter complex search terms and fetch contracts satisfying the search terms. Our Rippe & Kingston development team wanted this to be a tool that we could use on any of our custom projects and products. This tool was developed using ExtJS as the front end and C# ASHX pages to
process the query. This sounds really simple except when it was used in real
situations that fetch many thousand contracts. When this project was deployed
to a client that had more than 5000 contracts, we got the dreaded IE error “A
script on this page is causing Internet Explorer to run slowly”.
On
further research we determined that a script on our program was taking a long
time to finish executing. This is a note from Microsoft1 for
Internet Explorer - Because some scripts may take an
excessive amount of time to run, Internet Explorer prompts the user to decide
whether they would like to continue running the slow script. Some tests and
benchmarks may use scripts that take a long time to run and may want to
increase the amount of time before the message box appears. "
Now
there were a couple of options to resolve this error. One of the options
provided in the Microsoft Knowledge Base includes modification of a registry
value on client machines to wait for more time before throwing the notification
message. That option would introduce issues during mass deployment across large
client installations. Further, the same
script could also be running slower in other browsers as well.
The
other option was to go back to the drawing board and refactor2 the
script that was causing the issue. Refactoring is basically recoding the
program without affecting the end result of the program.
As
noted, the front end was ExtJS .
This consists of a Contract grid (A ExtJS Grid Panel) with default columns. The
users have options to choose the display fields that will be displayed as
columns on the grid. These display fields are saved on the Cache engine
behind our reporting tool. The Cache saves all the filters (Departments,
Companies, Users, Contract Types) used to filter the contracts and the display
fields that show up on the Contract Grid.
Our script calls a corresponding ASHX page
that processes the query and the query in turn uses the Cache to get the
fields. The filters selected/entered by the user generates the JSON object to
be returned to the script. The JSON object consists of the headers that will
recreate the ExtJS Grid.Panel columns and the data that will go to the ExtJS
store that populates the grid.
Since
the fields are not known until run time, the script was processing every header
field, recreating columns, filters, creating a store, paging tool bar and many
other things and finally adding the data to the store in the Grid Panel. This
took a lot of time.
// Comment function populateContractGrid(data) { // Code omitted ..... reconfigure_grid_test(newHeaders, newHeaderTypes, newData, dataStore); } //pass the information to the next method from here function reconfigure_grid_test(headers, types, data, dataStore) { // Code omitted ......... reconfigure_grid(headerFields, headerTypes, dataFields, dataStore); } function reconfigure_grid(fields, types, data, dataStore) { // Code omitted... //loop will create grid columns and grid fields, adding them to the above arrays // Code omitted columnArray.push(column); // Code omitted fieldArray.push(field); } //build the column model that will be used in the contract grid // Code omitted var reader = new Ext.data.ArrayReader( { totalProperty: '' }, record); var memoryProxy = new Ext.ux.data.PagingMemoryProxy(data); var store3 = new Ext.data.ArrayStore( { remoteSort: true, reader: reader, fields: fieldArray, baseParams: { lightWeight: true, ext: 'js' }, data: data, cm: columnModel, proxy: memoryProxy }); // Create the filters for the grid // Code omitted pagingTBar.bindStore(store3, true); contractGrid.reconfigure(store3, columnModel); if (contractGrid.plugins) { for (var index = 0; index <= contractGrid.plugins.length; index = index + 1) { contractGrid.plugins.pop(); } } filterPlugin.init(contractGrid); summary.init(contractGrid) contractGrid.plugins.push(filterPlugin); contractGrid.plugins.push(summary); // Code omitted }
Our
solution to this was to recreate the Grid Panel before fetching the JSON data
from the Query_Handler ASHX page and then replacing the store in the
Ext.Grid.Panel with the store recreated from the JSON Object returned by the
ASHX page.
So
basically when the user selected the fields for the Grid, the fields were saved
in the Cache by the DisplayFields_ASHX page and in return a JSON Object with
empty data rows was returned by this ASHX page. Our script used this JSON
Object to run the code displayed above with empty data (instead of more than
5000 records).
Then
when the query was run, the store of the ExtJS Grid Panel was just replaced
with the new store returned by the JSON object without recreating the grid.
That resulted in a dramatic change and the script was much faster in IE. Instead of calling the original code, we called a new function demonstrated below, where the store in the Contract Grid was replaced with the data from the JSON object.
// Comment function populateContractGridWithData(data) { // Code Omitted var newData = []; for (var i = 0; i < arrayRows.length; i++) { newData[i] = arrayRows[i].value; } var store4 = contractGrid.getStore(); var memoryProxy = new Ext.ux.data.PagingMemoryProxy(newData); store4.proxy = memoryProxy; pagingTBar.bindStore(store4, true); store4.load( { params: { start: 0, limit: 100 } });
This
design provided better user experience and also minimizes the need on system
resources.
In
summary, for slow operation of any code, one of the best options to resolve
these options is to go back to the drawing board and refactor the code to
improve speed without changing the external result or behavior of the code.
For more information check our website
References:
No comments:
Post a Comment