2

I'm using jqgrid on clienside for a financial web app where rows get added and/or updated very frequently (every few ms). Max number of rows always stays under 80. data gets pushed to the web through comet (reverse ajax) when data comes in, the following code is applied

update the jqgrid is defined this way:

jQuery(selector).jqGrid(
                {
                    datatype: 'local',
                    localReader: {
                        id: "id" 

                    },
                    colNames: ["id","price","volume","time"],
                    colModel: [ {name:'id', width:60},
                                {name:'price', width:80,
                                       align:"right",sorttype:"float"},
                                {name:'volume', width:100},
                                {name:'time',index:'amount', width:80} 
                                ], 
                    sortname: '', 
                    sortorder: 'desc',
                    height:'100%',
                    rowNum: 80,
                    viewrecords: true,
                    loadonce: true

                });

        ........................

_updateGrid: function (handle, args) { 
    var updated = args.data;
    var current = handle.jqGrid('getRowData', updated.id);
    if (typeof current.id == 'undefined' || current.id == null
                                         || current.id == "") {
        current = updated;
        var itWorks = handle.addRowData(updated.id, current);
    }
    else {
        handle.jqGrid('setRowData', updated.id,
                      {
                          id: updated.id
                          , price: updated.price
                          , volume: updated.volume
                          , time: updated.time
                      });
    }

    handle.sortGrid('price', false, 'desc');
}

right now the performance are very bad, so bad that firefox pops-up an error message requesting to stop the script.

I'm thinking of switching of grid widget, but before I would like to see if other developers have any idea that could solve the issue.

Alpha
  • 682
  • 10
  • 23

1 Answers1

0

In all performance problems it is important to localize the bottleneck.

I suppose that the problem is bad performance of the data sorting used in the jqGrid now. To verify this you can try set sortname parameter to "" and call handle.trigger("reloadGrid") instead of handle.sortGrid('price', false, 'desc');

If you will see that the refresh of data will work much more quickly then we can discuss about the corresponding solution. One will need to replace the _doSort method used to sort local data with more effective version (based of Quick Sort or probably Array.sort).

Another possibility to improve performance of your code is the use data and _index parameters of jqGrid to make direct access to the internal grid data. The _index parameter help you to get the index in the data array of data identified by rowid. After modification of all data you can trigger reloadGrid to refresh the grid.

Updated: With the code

var lastData = handle.jqGrid('getGridParam','data');
var dataIndex = handle.jqGrid('getGridParam','_index');

one can get the local data saved in the grid and its index. With

var i = dataIndex[updated.id], var current = null;
if (i>0) { current = lastData[i]; }

you get reference of the data element by rowid updated.id (I hope I understand your code correct and updated.id is the rowid).

Now you can make any modification of properties of the current element without need to save it. You work on place. After you made all modifications should just refresh the grid contain based of the modified data. You can do this with handle.trigger("reloadGrid") or with handle.sortGrid('price', false, 'desc'); which do the same.

Oleg
  • 220,925
  • 34
  • 403
  • 798
  • I tried _handle.trigger("reloadGrid")_, but no luck. still bad performance. could you elaborate more on how to use **data** and **_index** parameters. Thanks. – Alpha Mar 17 '11 at 22:14
  • @Alpha: I updated my answer. Are you sure that use don't use `handle.sortGrid('price', false, 'desc');` and used just used `handle.trigger("reloadGrid")` and that you has always `sortname:""`? Only with `sortname:""` jqGrid will do no sorting of data. – Oleg Mar 17 '11 at 22:36
  • @Oleg. you're right when sorting is not involved performance are ok. – Alpha Mar 17 '11 at 22:46
  • @Oleg, Regarding my code: Data are volatile, they're displayed and if updated they're gone, nothing is saved. Data comes row by row. so when a row "arrived" first I check if it's an existing row or if it is a new row. If new it gets added, if not it gets updated. then the grid is sorted appropriately. I don't see how **data** and **_index** could help me in this scenario – Alpha Mar 17 '11 at 22:55
  • @Alpha: Well. Now will be probably more difficult. First of all 80 rows of data is not much. You can try to post back **all** 80 rows, but **correct sorted** and then populate all the data. You can use `GridUnload` to remove the current grid (see [here](http://www.ok-soft-gmbh.com/jqGrid/RecreateGrid.htm) an example). I suggest this as the first option, because sorting in the database or in native code with quicksort can word quickly as in JavaScript. If if will be not possible you can try reimplement your own sorting based on code examples which you can easy find. I could help you with jqGrid – Oleg Mar 17 '11 at 22:56
  • @Alpha: You can just push new data items in the data array: `data.push(newItem)` and `_index[newItem.id]=data.length-1`. In the way you can easy add new rows. By the way probably you have additional performance in the parts of code where you "check if it's an existing row". How you do this? – Oleg Mar 17 '11 at 22:59
  • @Alpha: one more simple thing to improve the performance of the grid a little. Which value has `rowNum` (number of displayed rows)? Just try to set it to 5 or 10 (independent on your requirements) and see the performance. You can not show all 80 rows at once. So the scrolling or local paging of data is required. The local paging is much more effective. If all this will not help. You will be probably post more full your JavaScript code which you use with jqGrid. – Oleg Mar 17 '11 at 23:04
  • @Oleg: once can get the current array of data with _jqGrid.geRowData()_ with no parameters as described in the [documentation](http://www.trirand.com/jqgridwiki/doku.php?id=wiki:methods). Is there a way to inject an array of data? My idea is to use getRowData to access the array of data, do the custom sort and then re-inject the array in the grid. do you think this could work? – Alpha Mar 17 '11 at 23:08
  • @Alpha: It is difficult for me to give advices to you because **you don't posted how you define the jqGrid**. I don't know which datatype you use, whether you use local data paging and so on. In general the best performance in not to use `getRowData` which read all data from HTML page and unformat it. The the `getGridParam('data')` just get reference to the internal object and do nothing. You can receive it also with `$("#list")[0].p.data` if "list" is the grid id. – Oleg Mar 17 '11 at 23:15
  • @Oleg: I've updated the initial question with the definition of the Jqgrid. I'm using "local data", but in fact the data get injected as row comes in through comet(reverse ajax) script. – Alpha Mar 17 '11 at 23:38
  • @Alpha: The code is really simple. You can remove `localReader` and `loadonce` parameters because there contain default values. I would add `key:true` to the `id` column, but it nothing change. I don't know comet. So the only test will be rewrite `_updateGrid` like I described before. For example `if(!handle[0].p._index[current.id])` is better as `if(!handle.jqGrid('getRowData', updated.id))`. And so on... – Oleg Mar 17 '11 at 23:48
  • @Oleg: I'm trying to use _handle[0].p._index[current.id]_ but get p is undefined, does p represent something in the context of jqgrid? – Alpha Mar 18 '11 at 00:15
  • @Alpha: I supposed that `var handle=$("#list");`. Is it? Then `$("#list")[0].p._index` and `$("#list")[0].p.data` can be used. The `_index` is object and `data` is array. Try to use Developer Tools or Firebug and display in the watch window what you have in `$("#list")[0].p.data` and `$("#list")[0].p._index`. – Oleg Mar 18 '11 at 06:30
  • @Oleg: I figured out that one. By any chance do you know what is the max refreshing rate you can get with the grid? I think my issue may come from the fact too much data are coming in to be processed and it piles up to the point firefox can't handle it anymore. – Alpha Mar 18 '11 at 17:15
  • @Alpha: No! 80 rows is not much. 1000 rows can work OK. I though about your problem and made some tests with 1000 rows which works pretty good. Look at [this](http://www.ok-soft-gmbh.com/jqGrid/1000bound.htm) and [the next one](http://www.ok-soft-gmbh.com/jqGrid/1000boundSort.htm) where I inserted some alerts with the time information. Try this. First question which I forget to ask you yesterday: what web browser you used at your tests? – Oleg Mar 18 '11 at 17:30
  • @Oleg: I'm using mostly firefox 3.6, but same issue with ie9. when I say too much data, I'm talking about frequency. First comet is like ajax but instead of having the client requesting the data, it is the server that push the data to the client. So maybe if the push frequency is too high too much data have to be processed in a short among of time. – Alpha Mar 18 '11 at 19:10
  • @Alpha: If you use FF, it is very important to remove `.ui-widget :active { outline: none; }` from the jQuery UI css. Look at [the demo](http://www.ok-soft-gmbh.com/jqGrid/1000.htm). About 1,5 years ago I switched from Firefox to Google Chrome which is in the last version the most quick browser for JavaScript. Important is only **which browser use your customer**. Probably IE8? I would you recommend to make some tests based on my last example which I posted and prepared a demo **without comet**. I am not so sure that it make the main problem. I also strictly recommend you use local data paging – Oleg Mar 18 '11 at 19:28
  • @Oleg: thanks for all your help, I'm going to try your last recommendations and see how it goes. why removing `.ui-widget :active { outline: none; }` should help? I'm curious to understand how a style impact the update of the grid. – Alpha Mar 18 '11 at 22:31
  • @Alpha: There are known problem about which you can read [here](http://www.trirand.com/blog/?page_id=393/bugs/compatibility-bug-with-jquery-ui-1-8-4/) - just try the tests, [here](http://stackoverflow.com/questions/3883328/jqgrid-multiselect-is-very-slow-with-large-local-data-and-jqueryui-1-8-jqueryui) and [here](http://bugs.jqueryui.com/ticket/6757). The problem is not in the update the grid, but in **general performance of painting in mostly Firefox**. If your browser work much slower it can make all your problems more difficult to solve. I think you should know about the problem. – Oleg Mar 18 '11 at 22:45
  • @Oleg: thanks for the info. it's very impressive. It must have been a long debugging session to find that one. – Alpha Mar 19 '11 at 00:12