#124 bug
Rodrigo Rosauro

Ajax request consumes huge memory (1GB+) for big responses

Reported by Rodrigo Rosauro | May 29th, 2008 @ 03:59 PM | in 1.6.1

I'm using "Ajax.Request" to get a big (4 MB) XML file from the server with Firefox (2 and 3RC1) and prototype.js 1.6.0.2.

Every time this ajax call is performed, the browser hangs for around a minute and the memory consumption grows up to ~1GB.

At first I thought this was a FF problem, but just to be sure I tested using only the native XMLHttpRequest object, getting for my surprise an absolutely instantaneous response without any visible memory consumption.

After some investigation I found that the cause of the problem relies on line #1361 (the Ajax.Response constructor). Here follows the problematic code:

    if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
      this.status       = this.getStatus();
      this.statusText   = this.getStatusText();
      this.responseText = String.interpret(transport.responseText); // <- problem
      this.headerJSON   = this._getHeaderJSON();
    }

Since Firefox sends a "readyState" 3 for every 4096 bytes read, the "transport.responseText" property is accessed many times during the request execution, and every time this native property is accessed, the browser needs to create a new (big) JavaScript String instance with its contents.

In order to fix MY problem, I just removed the verification of readyState 3 (because I don't need any data when this status arrives), but a more general solution could be to just move line #1361 to the next "if" (which checks explicitly for readyState 4.

My final code (modified):

Ajax.Response = Class.create({
  initialize: function(request){
    this.request = request;
    var transport  = this.transport  = request.transport,
        readyState = this.readyState = transport.readyState;

    if(readyState == 4) {
      this.status       = this.getStatus();
      this.statusText   = this.getStatusText();
      this.responseText = String.interpret(transport.responseText);
      this.headerJSON   = this._getHeaderJSON();
      var xml = transport.responseXML;
      this.responseXML  = Object.isUndefined(xml) ? null : xml;
      this.responseJSON = this._getResponseJSON();
    }
  },

Proposed general-solution code:

  initialize: function(request){
    this.request = request;
    var transport  = this.transport  = request.transport,
        readyState = this.readyState = transport.readyState;

    if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
      this.status       = this.getStatus();
      this.statusText   = this.getStatusText();
      this.headerJSON   = this._getHeaderJSON();
    }

    if(readyState == 4) {
      this.responseText = String.interpret(transport.responseText);
      var xml = transport.responseXML;
      this.responseXML  = Object.isUndefined(xml) ? null : xml;
      this.responseJSON = this._getResponseJSON();
    }
  },

Comments and changes to this ticket

Please Login or create a free account to add a new comment.

You can update this ticket by sending an email to from your email client. (help)

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

The Prototype JavaScript library.

Shared Ticket Bins