views:

22

answers:

0

I am using a dojox.grid.DataGrid with a dojox.data.QueryReadStore. As the user scrolls the grid, the grid lazy loads rows from the store and keeps them in memory. Using Firefox on Linux or IE 7 or 8 on Windows, it appears that these rows are never cleared, and the footprint of the browser window will continue to grow (as observed in top or Task Manager). IE is my biggest concern as it is used by all of my user base.

I've stumbled upon the DataGrid's _clearData() method, but that does not seem to solve the problem. It clears the grid, but the footprint does not seem to shrink.

I set up a simple example of this using Matthew Russell's article on using a dojox.data.QueryReadStore with a Data Grid:

http://www.oreillynet.com/onlamp/blog/2008/04/dojo_goodness_part_6_a_million.html

I have updated the code to use the newer 1.4 DataGrid but still used the simple python webserver for a basic example.

Here's my isolated DataGrid example:

<html>

  <head>

    <title>Memory Leak Demo</title>


    <link rel="stylesheet" href="http://o.aolcdn.com/dojo/1.4/dijit/themes/nihilo/nihilo.css"&gt;
    <link rel="stylesheet" href="http://o.aolcdn.com/dojo/1.4/dojo/resources/dojo.css"&gt;
    <link rel="stylesheet" href="http://o.aolcdn.com/dojo/1.4/dojox/grid/resources/Grid.css"&gt;


    <script

      type="text/javascript"

      src="http://o.aolcdn.com/dojo/1.4/dojo/dojo.xd.js"

      djConfig="parseOnLoad:true"

    ></script>



    <script type="text/javascript">

      dojo.require("dojox.data.QueryReadStore");

      dojo.require("dojox.grid.DataGrid");

      dojo.require("dojo.parser");



      // a simple grid layout that consists of 5 columns

      layout = [

          {name:'ID',field:'id',width:'5'},

          {name:'Item',field:'item',width:'auto'},

          {name:'Quantity',field:'quantity', width:5},

          {name:'Cost',field:'cost', width: 5 },

          {name:'Total',field:'total', width: 5}

      ];



    </script>

    </head>

    <body class="nihilo" id="body">



        <!-- The dojo.data API implementation that talks to the server -->

        <div dojoType="dojox.data.QueryReadStore" id="store" jsId="store" url="/data"></div>





        <!-- The grid, which relies on its DojoData abstraction for info -->

        <div style="height:300px; width:400px;" dojoType="dojox.grid.DataGrid"  structure="layout" delayScroll="true" rowsPerPage="20" store="store"></div>



    </body>

</html>

And here is the simple web server that Matthew demonstrated for delivering the page and responding to DataGrid queries (if you want to set it up, reference his article linked above):

"""
An ultra-simple web server that provides slices of a very large (mock) data
source for a dojox.grid.Grid client that uses a dojox.data.QueryReadStore
to page the data on demand
"""

import cherrypy #do an "easy_install cherrypy" to get it
from cherrypy.lib.static import serve_file

import demjson #do an "easy_install demjson" to get it
import os
from random import randint #for building up mock data

json = demjson.JSON(compactly=False)
jsonify = json.encode

NUM_ITEMS = 1000000

class Content:
    def __init__(self):
        """
        maybe you would call out to a db with some sql to get some data
        based on the query string that comes into /data. for now, we'll
        build up some static data to use.
        """

        self.items = []

        possible_item_names = ["Foo", "Bar", "Baz", "Bop"]
        id=0
        for i in xrange(NUM_ITEMS):
            self.items.append({
                    'id' : id,
                    'item' : possible_item_names[randint(0,3)],
                    'quantity' : randint(0,10),
                    'cost' : randint(0,100)
            })
            id +=1

        #keep track of sort order b/c sorting is expensive...
        self.current_sort_order = ""

    @cherrypy.expose
    def data(self, **kw):
        """
        serve up the data via http://localhost:8000/data

        kw will contain whatever is in your store's query. by default
        the query string will come across as something like:
        ?name=*&start=0&count=20 to populate the table 

        note: you may get into trouble if you have multiple users
        trying to access this url and changing the sort order of items
        all at the same time (but relax, this is just a little demo.)
        """

        #sorting the items by values for a given dictionary key...
        if kw.get('sort') and self.current_sort_order != kw.get('sort'):
            if kw['sort'][0] == '-': #descending order, slice off the -
                self.items.sort(lambda m,n:cmp(m.get(kw['sort'][1:]), n.get(kw['sort']    [1:])),reverse=True)
           else: #ascending order
                self.items.sort(lambda m,n:cmp(m.get(kw['sort']), n.get(kw['sort'])))
            self.current_sort_order = kw['sort']

        #slicing the data...
        start = int(kw['start'])
        end = start + int(kw['count'])

        #serving up the slice of interest as well as the total size
        return jsonify({'numRows':NUM_ITEMS, 'items':self.items[start:end]})

    @cherrypy.expose
    def grid(self, **kw):
        """
        Serve up the web page through http://localhost:8000/grid
        """
        return serve_file(os.path.join(os.getcwd(), 'grid.html'))

cherrypy.server.socket_port = 8000
cherrypy.quickstart(Content(),'/')