最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - XMLHttpRequest - freeing after use? - Stack Overflow

programmeradmin8浏览0评论

I'm writing a browser app that would be entirely AJAX-driven (first time in my life), that means:

  • it will be one page staying in the browser, loading program ponents as needed
  • browser history will be, well, none.
  • page will not be refreshed at all

My concern is what should I do about XMLHttpRequests, since I'm primarily C++ programmer, being taught that when you write a statement like

x = new XMLHttpRequest();

you need to delete it afterwards.

This question is entirely about memory management, whether this object, allocated with new stays in memory, even after it finishes it's "cycle" with readyState == 4 or is somehow released, freed, whatchacallit? Honestly, I have no idea at what point could it be freed, since the script creating these will be in HEAD and sit there potentially whole workday. Whether should I:

  • create one or several, reused objects of type XMLHttpRequest, program the app so that it won't need any more than this limit,
  • or it doesn't matter and I can allocate as many new XMLHttpRequests as I like?

Please include in your answers at what point and WHY those objects would be deleted, if they would at all, considering that the "frame" of my webpage will stay. Hope I made this question clear and thanks for any insightful answers.

EDIT:

Consider code (I removed many lines that were checking for unexpected return values for brevity) of an onClick event handler, that creates XMLHttpRequest and sends it:

function submitme(){  
  var p = document.getElementById('p'); //a text field being sent to server
  if(typeof p!='undefined' && p!=null){
    if(p.value!=""){
      //here XMLHttpRequest is created, this function
      //returns exactly object of this type or false, when failed
      var xhr=createXmlHttpRequestObject();
      if(xhr!=false){
        xhr.open("POST", "blablabla.php", true);
        xhr.onreadystatechange=function(){
          if(xhr.readyState==4){
             if(xhr.status==200){
               //result will be posted in this div below
               var adiv = document.getElementById('resultdiv');
               //extract the XML retrieved from the server
               xmlResponse = xhr.responseXML;
               //obtain the document element (the root element) of the XML structure
               xmlDocumentElement = xmlResponse.documentElement;
               //get the response text
               if(typeof adiv !='undefined' && adiv != null){
                  adiv.innerHTML=xmlDocumentElement.childNodes[0].firstChild.nodeValue;
               }
             }//end xhr.status
           }//end xhr.readyState
         };//end xhr.onreadystatechange
         xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
         xhr.send(p.value);
       }//end xhr!=false
     }//end p.value!=""
   }//end typeof p!='undefined'
 }//end submitme()

When XMLHttpRequest object instance is created, if this handler is fired, it is referenced once by xhr variable until handler finishes to execute. At this point there are how many references to this object instance? If I understand articles linked in your answers correctly, the answer should be none, and browser just waits for this request to turn readystate==4, finish executing onreadystatechange function and object is unreachable? Please confirm.

I'm writing a browser app that would be entirely AJAX-driven (first time in my life), that means:

  • it will be one page staying in the browser, loading program ponents as needed
  • browser history will be, well, none.
  • page will not be refreshed at all

My concern is what should I do about XMLHttpRequests, since I'm primarily C++ programmer, being taught that when you write a statement like

x = new XMLHttpRequest();

you need to delete it afterwards.

This question is entirely about memory management, whether this object, allocated with new stays in memory, even after it finishes it's "cycle" with readyState == 4 or is somehow released, freed, whatchacallit? Honestly, I have no idea at what point could it be freed, since the script creating these will be in HEAD and sit there potentially whole workday. Whether should I:

  • create one or several, reused objects of type XMLHttpRequest, program the app so that it won't need any more than this limit,
  • or it doesn't matter and I can allocate as many new XMLHttpRequests as I like?

Please include in your answers at what point and WHY those objects would be deleted, if they would at all, considering that the "frame" of my webpage will stay. Hope I made this question clear and thanks for any insightful answers.

EDIT:

Consider code (I removed many lines that were checking for unexpected return values for brevity) of an onClick event handler, that creates XMLHttpRequest and sends it:

function submitme(){  
  var p = document.getElementById('p'); //a text field being sent to server
  if(typeof p!='undefined' && p!=null){
    if(p.value!=""){
      //here XMLHttpRequest is created, this function
      //returns exactly object of this type or false, when failed
      var xhr=createXmlHttpRequestObject();
      if(xhr!=false){
        xhr.open("POST", "blablabla.php", true);
        xhr.onreadystatechange=function(){
          if(xhr.readyState==4){
             if(xhr.status==200){
               //result will be posted in this div below
               var adiv = document.getElementById('resultdiv');
               //extract the XML retrieved from the server
               xmlResponse = xhr.responseXML;
               //obtain the document element (the root element) of the XML structure
               xmlDocumentElement = xmlResponse.documentElement;
               //get the response text
               if(typeof adiv !='undefined' && adiv != null){
                  adiv.innerHTML=xmlDocumentElement.childNodes[0].firstChild.nodeValue;
               }
             }//end xhr.status
           }//end xhr.readyState
         };//end xhr.onreadystatechange
         xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
         xhr.send(p.value);
       }//end xhr!=false
     }//end p.value!=""
   }//end typeof p!='undefined'
 }//end submitme()

When XMLHttpRequest object instance is created, if this handler is fired, it is referenced once by xhr variable until handler finishes to execute. At this point there are how many references to this object instance? If I understand articles linked in your answers correctly, the answer should be none, and browser just waits for this request to turn readystate==4, finish executing onreadystatechange function and object is unreachable? Please confirm.

Share Improve this question edited Feb 4, 2014 at 19:12 Kitet asked Feb 4, 2014 at 13:50 KitetKitet 8832 gold badges10 silver badges20 bronze badges
Add a ment  | 

6 Answers 6

Reset to default 9

I have recently hit the same problem, and I have found all around the Internet that I should not have any concerns, because it is garbage collected. Well, you SHOULD have concerns, because it is quite easy to leave some references around, if you just got it work for the first time.

See this page:

http://javascript.info/tutorial/memory-leaks

and scroll down to "XmlHttpRequest..."

What it basically says:

IF you create a new xhr object every time (do not reuse them) AND capture each xhr object in the closure of the respective onreadystatechange callback THEN the xhr object will never be garbage collected, and the memory leak will ramp up.

To avoid this situation, use the this to access the xhr object (e.g. to check state), and get the xhr out of the closure.

http://xhr.spec.whatwg/#garbage-collection - here is the answer to your question. This is part of specification (how it has to be implemented, but this is not 100% sure how it is implemented in all browsers), to understand it more deeply advice you to read the hole document

An XMLHttpRequest object must not be garbage collected if its state is OPENED and the send() flag is set, its state is HEADERS_RECEIVED, or its state is LOADING, and one of the following is true:

It has one or more event listeners registered whose type is readystatechange, progress, abort, error, load, timeout, or loadend.

The upload plete flag is unset and the associated XMLHttpRequestUpload object has one or more event listeners registered whose type is progress, abort, error, load, timeout, or loadend.

If an XMLHttpRequest object is garbage collected while its connection is still open, the user agent must terminate the request.

JavaScript has an automatic built-in garbage collector.

You might want to read this article:

JavaScript has garbage collection, just let the reference to the XHR object drop out of scope and it should get cleaned up automatically.

XMLHttpRequest is nothing special as far as object lifetime is concerned. As any other object, it will be garbage-collected when you drop the last reference to it.

The possibly unusual or unfamiliar thing with XMLHttpRequest is the lifetime you are required to insure for an Ajax request to work properly.

Basically you need to have a live XMLHttpRequest object during all the lifetime of the underlying Ajax request.

Once the request is plete, you are free to delete the object or reuse it for another query.
This scenario is often used by people who do not want to bother with memory management :).

If you need to have multiple requests at once, you will need more than one XMLHttpRequest object.
In that case, you will probably want to manage the life time of each XMLHttpRequest object more precisely (either returning it to a pool of free request handlers or deleting it).

In my case I had to test the server side of downloading a lot of big images. I didn't actually need to keep or do anything with the returned buffer on the client browser side. I found that not assigning the response to anything for some reason dramatically enhances garbage collection

Here is the code I use which also have pooling and timeout:

// not using fetch so that we can add a timeout
// pool XMLHttpRequest connections 
// if discard==true resolves with undefined but greatly increases GC
const fetchx = async (url, postbufToJson, discard=false) => {
  if (!fetchx.stack) { // create pool
    fetchx.stack = new Array()
    fetchx.nullFunction = () => {}
    fetchx.stack.get = () => fetchx.stack.length < 1 ? new XMLHttpRequest() : fetchx.stack.pop()
    fetchx.stack.free = xhr =>  {
      xhr.onerror = xhr.onload = xhr.onreadystatechange = fetchx.stack.nullFunction
      fetchx.stack.push(xhr)
    }
  }
    
  return new Promise((resolve, reject) => {
    var xhr = fetchx.stack.get()
    xhr.timeout = 20 * 60 * 1000
    xhr.onload = () => {
      if (xhr.status >= 200 && xhr.status < 300) {
        console.log(`${xhr.status} ${xhr.responseURL}`)
        let response = discard ? undefined : xhr.response
        fetchx.stack.free(xhr)
        resolve(response)
      } else {
        console.log(`${xhr.status} ${xhr.responseURL}`)
        let status = xhr.status
        let statusText = xhr.statusText
        fetchx.stack.free(xhr)
        reject({ status, statusText })
      }
    }
    xhr.onerror = () => {
      console.log(`${xhr.status} ${xhr.responseURL} ${xhr.statusText}`)
      let status = xhr.status
      let statusText = xhr.statusText
      fetchx.stack.free(xhr)
      reject({ status, statusText })
    }

    if (postbufToJson) {
      xhr.open('POST', url, true)
      xhr.setRequestHeader('Content-type', 'application/json; charset=utf-8')
      xhr.send(JSON.stringify(postbufToJson))
    } else {
      xhr.open('GET', url, true)
      xhr.send()
    }
  })
}
发布评论

评论列表(0)

  1. 暂无评论