An XMLHTTPRequest tip


Over on the Ajax Blog, Dion Almaer passed on an important tip from Brent Ashley and Tim Aiello for AJAX developers – to have your cross-browser AJAX work better with IE7, you really should be invoking the native XMLHttpRequest (the cross-browser one) first to see if it’s available before instantiating the ActiveX control, instead of the other way around.

In addition to the reasons that Brent and Tim discovered, I’ve seen a bunch of code that creates the XMLHttpRequest object, uses it for a request, and then throws it away.  Obviously, this is a lot less performant than keeping the object around for multiple requests.  The native object’s lifetime can be as long as that of the page. So you can reuse it like this:

            var  o = new XMLHttpRequest()
            o.open(“GET”, “data1.xml”,  true);
            o.onreadystatechange = foo();
            o.send();
            …….
            o.open(“GET”, “data2.xml”,  true);
            o.onreadystatechange=bar();
            o.send();

Xmlhttp.open has a “reset” semantic so the second open() call on the same object will abort the previous connection, disconnect previous event handler, and reset the object.

There’s also a handy tool by Julien Couvreur for debugging XHTMLHTTPRequest calls for IE, or you can use Fiddler.

-Chris

Edit: Changed XMLHttpRequestObject() to XMLHttpRequest() in code illustration.

Comments (62)

  1. Dean Edwards says:

    You would gain a lot more credibility if you used "true" instead of "TRUE".

  2. ieblog says:

    Well, that’s what I get for copying and pasting someone else’s example.  Corrected.

    -Chris

  3. if (!window.XMLHttpRequest) {

       window.XMLHttpRequest = function() {

           return new ActiveXObject("Microsoft.XMLHTTP");

       };

    }

  4. Dao says:

    That’s good, Matthew. Exactly what I do. :)

    And now let’s pimp it with conditional compilation since no other browser than IE provides ActiveXObject:

    /*@cc_on @if (@_win32 && @_jscript_version >= 5) if (!window.XMLHttpRequest)

    function XMLHttpRequest() { return new ActiveXObject(‘Microsoft.XMLHTTP’) }

    @end @*/

    ( http://en.design-noir.de/webdev/JS/XMLHttpRequest-IE/ )

  5. Mister Lucky says:

    your foo() and bar() are a bit misleading, they should really be function pointers, not return values of functions.

    unless the functions themselves return functions :)

    but may become a closure memory leak for IE if such!! ;)

  6. Julian Reschke says:

    Hm.

    I would agree with the proposal, if IE7’s XMLHttpRequest would have the same functionality as the MSXML’s version of it (see https://connect.microsoft.com/feedback/ViewFeedback.aspx?SiteID=136&FeedbackID=83800).

    Best regards, Julian

  7. Dao says:

    Mister Lucky is right, of course. It should be o.onreadystatechange = foo;

    By the way, as the request is most likely asynchronous, isn’t overwriting onreadystatechange after calling send() a little bit dangerous?

  8. santosj says:

    Damn, I was wondering why everyone was trying to call the ActiveX version when IE 7 was going to have the XMLHttpRequest object.

    For once, I was able to predict the outcome. But I suppose it is bittersweet since I totally suck at JavaScript.

  9. lahmatiy says:

    another one

    getTransport = function(){

     var __transport = new Array(

                                 function(){ return XMLHttpRequest ? new XMLHttpRequest() : null },

                                 function(){ return ActiveXObject  ? new ActiveXObject(‘Msxml2.XMLHTTP’) : null },

                                 function(){ return ActiveXObject  ? new ActiveXObject(‘Microsoft.XMLHTTP’) : null }

                                );  

     for (var i = 0; i < __transport.length; i++)

       try {

         if (__transport[i]())

           return __transport[i];

       } catch(e) {}

     return function(){ return null };

    }();

  10. EricLaw [MSFT] says:

    @Dao: Without seeing foo and bar it’s of course impossible to say, but yeah, unless these functions themselves return functions, they should be referenced without parentheses.

    The request is asynchronous (the third parameter is true), so what happens in the "…" is pretty critical to how this code behaves.  

    As noted above: "Xmlhttp.open has a “reset” semantic so the second open() call on the same object will abort the previous connection, disconnect previous event handler, and reset the object."

    If you were to run the code above and sniff the HTTP traffic, you’d see that the first HTTP request usually doesn’t even make it out to the wire.  

    The spec for XMLHTTP requires that an asynchronous send return "immediately" which means that it can’t even block until the request bytes are on the wire.

  11. bullsh_it says:

    To people who complain about this:

    For security’s sake, please, no more activex. You knew IE 7 will not allow activex run by default, your gadget won’t run properly because of that, your gadget won’t be able to run in other browsers.

  12. Dao says:

    lahmatiy, I don’t see the benefit. Looks bloated to me ;)

  13. Attila Szabo says:

    "I’ve seen a bunch of code that creates the XMLHttpRequest object, uses it for a request, and then throws it away."

    I read the following in "The JavaScript Anthology" book by Sitepoint:

    "Even though the XMLHttpRequest object allows you to call the open method multiple times, each object can be used effectively only for one call, as the readystatechange event does not occur again once readyState changes to 4 (in Mozilla).".

    Of course in case of MS IE you really should not recreate the object again. A wrapper function or method should take care of this and many more differences between browsers.

  14. cooperpx says:

    @ Dao

    lahmatiy’s implementation is pretty cool. It constructs a function that does not continually check the browser capabilities and will create the preferred version of the xml request object.

    It’s also centralized, so all your code will get ‘fixed’ or updated should a new transport platform get made (such as a flex-bridge transport). Theoretically, lahmatiy could also implement a xmlhttprequest look-alike object that uses frames.

  15. Steve says:

    Ok, can we at least get the sample fixed?

    var o = new XMLHttpRequest();

    o.open(‘GET’, ‘data1.xml’,  true);

    o.onreadystatechange = foo;

    o.send();

    …….

    o.open(‘GET’, ‘data2.xml’,  true);

    o.onreadystatechange = bar;

    o.send();

    /*

     added ; to first line,

     changed foo and bar to references, not calls

     (glad to see the TRUE now set to true, as

     mentioned, using TRUE looks extremely

     amatuer)

    */

    One side note.  In IE7 (for reasons I simply can not fathom, there is an option, (tools > options) to [_] Disable native XMLHttpRequest.

    HUH?!, so, you decide to play catch up, and support this natively, and then add an option to kill it?

    If this is some backwards way of implementing security that isn’t required, I just don’t get it.  Will there be a checkbox to disable HTTP 1.1?

    Steve

  16. Robin says:

    "Will there be a checkbox to disable HTTP 1.1?"

    As in Tools / Internet Options / Advanced / HTTP 1.1 Settings / Use HTTP 1.1? :)

  17. Mister Lucky says:

    " Xmlhttp.open has a “reset” semantic so the second open() call on the same object will abort the previous connection, disconnect previous event handler, and reset the object. "

    Would this mean that an abort() would be called during the new open() call??

    seems the abort(), might allow for a quick tidy-up of the pre-existing request, if it is still outstanding??

    or, a "best practices" is to call abort() manually when readyState && < 4?? then proceed to reuse the request by calling a fresh open()?

  18. Dao says:

    > lahmatiy’s implementation is pretty cool. It constructs a function that does not continually check the browser capabilities and will create the preferred

    > version of the xml request object.

    As do Matthew Ratzloff’s and mine implementations. They are just smaller, faster and easier to use.

  19. nomad513 says:

    lahmatiy’s implementation looks like a copy/paste job from the prototype.js library, combining the Ajax.getTransport function with the Try.these function.

  20. ieblog says:

    @Steve –

    Yes, we provided a user option to disable this.  If the user/admin does not want the old XMLHTTPRequest, they can disable it (by disabling ActiveX).  We wanted to make sure they still had the ability to disable the native version if they so chose. -Chris

  21. And now that we have client-side support for XSLT in EVERY major browser (IE,Mozilla,Safari,Opera(in 9.0)) we can avoid ALL of this "if" guess work and slim down our apps to focus on access the code base that is specific to their individual ways of handling the various tasks we ask of it:

    http://www.xsltblog.com/archives/2005/12/finally_someone_1.html

  22. By the way… for those who would rather avoid the 20 page jibber-jabber post, and simply see a quick demo of what I am refering to that works in IE, Safari, and Mozilla, visit http://browserbasedxml.com

    If you view source you will find access to the XML and a link to the XSLT file and pretty much be enabled to figured out the rest from there.

    In regards to Opera 9.0, the latest weekly build release is still returning:

    XSLT – http://browserbasedxml.com/SessionConfig.xsl

    attribute at line 13, column 40

    Error: invalid expression: document(my:UserAgentInvalidDoc)

    Call to undefined function: document

    They’ve stated they plan support for XSLT/XPath 1.0 in the final release, and given that the document function is very much a part of XSLT/XPath 1.0 I can only assume this will be fixed by the time they release.

    None-the-less… time will tell.

  23. lahmatiy says:

    @ nomad513

    Yes, you are right, implementation looks like some functions from the prototype.js library. But this library don’t optimized and:

    1. do selection of transport constructor every time while create Ajax.Request object

    2. instead of native XMLHttpRequest it’s use ActiveX

    Anyway, you couldn’t write something really new :) I’m just want to show implemetation looks more pretty than using conditional comments.

  24. Steve says:

    @Robin:

    uhm, yeah, what I was going for, was:

    <sarcasm_factor>

    Where’s the option to disable HTTP? I mean if you are going to blog native XMLHttpRequests, why can’t you disable HTTP Request/Responses?  The whole idea behind blocking the native XMLHttpRequest is obsurd.

    </sarcasm_factor>

    @ieblog:

    Thanks Chris, yeah, I realize (and appreciate) that the ActiveX version can be disabled… this makes total sense.  However disabling Native XMLHttpRequest, appears to only do one of thing:

    a.) Indicates that MS feels there may be a security hole in its implementation, and therefore wants to add an option to disable it, should there be a zero-day exploit that warrents informing end users.

    Please tell me, that the Native implementation isn’t just some sort of "secure" wrapper on the ActiveX version!… what gives?

  25. EricLaw [MSFT] says:

    In general, almost all new IE features have an option to control whether or not the feature is enabled.  

    Say a company decides that they don’t want XMLHTTP available on their network for some reason (and rest assured, companies want all sorts of "interesting" things).  

    Now, in the old days, you could simply disable the object or disable ActiveX. Since we’ve added a native implementation, some company is going to ask for a way to disable that too.  So we’ve added one.  

    We don’t expect that any normal user is likely to uncheck this, and in fact, very few users will even see the option at all.  

    (And to be clear, there’s nothing wrong with the ActiveX version of XMLHTTP; the window-Native version has been added for simplicity in developing AJAX sites).

  26. samlakshmi says:

    I think this may be a little out of place but I think its worth informing:

    IE6 crashes when vml is fetched using XMLHTTP and shown using objDiv.innerHTML = objXMLHTTP.reponseText.

    The event log says:

    Faulting application IEXPLORE.EXE, version 6.0.3790.1830, faulting module vgx.dll, version 6.0.3790.1830, fault address 0x000ab694.

    I know that MS has released a fix to this issue for WinXP SP2 systems (KB Article ID: 885932).

    But I would just like to point out that this occurs often on Windows Server 2003 + SP1 too.

    Any ideas when can we get a patch for this?

  27. What about DOMParser, XMLSerializer, document.implementation.createDocument etc? Without those we will continue to rely on ActiveX being turned on to achieve the same things.

    As far as I know Dave Massey promised that these would be added as well. However, it seems that marketing and not real world need has been driving IE7 features when it comes to the APIs.

  28. Dao says:

    > I’m just want to show implemetation looks more pretty than using conditional comments.

    You can leave out the conditional compilation thing if you don’t like it (see Matthew Ratzloff’s code.)

    Three lines of code making `new XMLHttpRequest;` functional in IE 5.5 and 6. How’s what you’ve posted prettier?

  29. EricLaw [MSFT] says:

    @Erik– Dave made no such promise for IE7.  He did promise that we’d add them to our list for consideration in a future release.

    I’m not sure where you got the notion that marketing had anything to do with this.

  30. 这一年多来Vista有不少版本都在我机器上借宿过,从早期巨慢无比到beta1时我的显卡也能跑Aero了.现在RTMBusiness版也占据了我的硬盘的一部分。但是无论什么时候,总是感觉在Vista上…