Wednesday, April 18th, 2007
Category: Ajax
, Tip
<
>p
>In low-level land, the try/catch trick that Prototype uses was king for 'most fun way to get the XHR object'.
Nicolas Faugout has put his hat in the ring with:
JAVASCRIPT:
-
-
if (!XMLHttpRequest) {
-
function XMLHttpRequest() {
-
return new ActiveXObject('Microsoft.XMLHTTP');
-
}
-
}
-
This feels like the Just Another Perl Hacker hacks in Perl land. Next we will see examples with rot13.
- XHR
XMLHttpRequest, also called XHR, is an application program interface (API) that was first used by Microsoft in version 5.0 of its Internet Explorer...
- XMLHttpRequest
XMLHttpRequest, also called XHR, is an application program interface (API) that was first used by Microsoft in version 5.0 of its Internet Explorer...
- Distinguishing a faked XMLHTTP request from a real one
When verifying XMLHTTP requests, don't depend on your Web application to determine the difference between real and fake. Web services security expert...
- Definition of data abstraction and data abstraction layers
Data abstraction simplifies database design. Learn the definition of data abstraction and find out the three formal kinds of abstraction layers, from...
- Ajax Web application development celebrates fifth anniversary
The term "Ajax" was first used five years ago in a blog entry by Jesse James Garret. We spoke with Garret and other Ajax pioneers and users about the...
This is so neat! Expect jQuery and MochiKit to be pouncing on this and adding it to their library.
/me looks at date – nope, the 1st has been well gone.
why is this news? the try/catch thing used by most frameworks is because Microsoft.XMLHTTP is not always available (depends on the version of MSXML, or something).
by removing the other versions, you will be restricting your IE audience.
Returning from a constructor is not exactly something you’re supposed to do. It might work in IE, but it won’t work in other browsers.
There is a reason behind using the try catch other than determining version suport:
http://radio.javaranch.com/pascarello/2006/02/07/1139345471027.html
Some assumptions you might have taken, but are wrong:
On IE6,
!XMLHttpRequestdoesn’t return false here.That’s because IE reads the “function”s on the page before running thru the code. It means, it reads the code, finds all the functions and makes the
functions list for the current scope. When it gets to “function XMLHttpRequest” it defines window["XMLHttpRequest"]=function () { … } (window is the
current scope). Only THEN, after declaring the functions, it goes thru the whole code from line 1.
This is NOT true for Gecko.
function a() {
alert("a");
}
if (false) function a() {
alert("b");
}
a();
In the above code, IE will shout “b”, and FF will shout “a”. That is because what I explained before.
Accessing to a() is available before “function a()” is declared, and IE takes the LAST declaration no matter where it is (assuming it’s in the same scope).
FF declares the if statement as scoped statement.
The following code will explain:
a();
if (true) {
function a() {
alert("a");
}
a();
}
function a() {
alert("b");
}
For FF, the result is “b”, “a”.
For IE6, it’s “b”, “b”.
On IE then, the !XMLHttpRequest returns TRUE because it is declared.
FF ignores the statement because XMLHttpRequest does exist and as mentioned before, doesn’t declares “function XMLHttpRequest” as a functions.
BTW, declaring “f=function ()” is different than “function f()”. The latter is accessible from everywhere in the same scope, unlike the first that accessible only after being declared.
this is what i use
its in the constructor of the core ajax “query” class
//————————————————————–
// constructor
//————————————————————–
this.setGlobals = function(){
if(window.ActiveXObject){isIE = true;}
objREQ = isIE == false ? new XMLHttpRequest() : new ActiveXObject(“Microsoft.XMLHTTP”) ;
my_AJAX = this;
}
A little explaination on my code :
- Elad, I don’t see any incompatibility between what you say and my code. Think about the !XMLHttpRequest beeing here for FF not to redefine XMlHttpRequest.
As for IE, if the function is declared during the reading process you described, that’s great, because it is what we want on IE ;)
- Kae, I agree with you, this code need some diggin
What I wanted to introduce, after the if then else checking browser version stuff and the magic try/catch Prototype solution is a new approach that would consist of defining once for all (at run time) a function named XMLHttpRequest in order not to introduce a new name for instanciating AJAX calls (when not using any framework of course).
Feel free to adapt the idea to your needs (several ActiveXObject uses, etc..)
@Nicolas – That’s bad programming, relying on a logical error, even if it works. Besides, like @Jonathan said, it’ll overwrite IE7′s native object.
If it wasn’t the XMLHttpRequest, or “else” clause would’ve been written, as I mentioned in my code – the two browsers would present different results.
You can put a bit more characters and make it work as it should be and still maintaining the ‘good programming’, by asking for ‘window.XMLHttpRequest’ and assigning to it.
if (!window.XMLHttpRequest) {
window.XMLHttpRequest=function () {
return new ActiveXObject('Microsoft.XMLHTTP');
}
}
I really appreciate staying away from prototype’s ridiculous try/catch technique. It triggers firebug because there is an error for each XHR request. I only visit Ajaxian with IE because of that.
@Elad – I owe you one! I didn’t know IE was reading the script AND assigning functions as it discovers them even neasted in the code. Your version of course solves the IE 7 issue.
@Jonathan, I get this in Firefox:
new function(){return 1} -> [object Object]
5 * (new function(){return 1}) -> NaN
@Kris Zyp,
Um… I’ve never had Firefox/Firebug generate an error using Prototype, nor accessing its Ajax object. Not once.
@Mark – that’s because new operator returns the object itself, which is not 1 but an instance of the function, regardless the ‘return’ statement.
To achieve that kind of syntax, you should override the valueOf method, like this:
function GetFive() {}
GetFive.prototype.valueOf=function () { return 5; }
alert(5*new GetFive());
(very similar like overriding the toString method).
@Kris – Why don’t you just disable Firebug for Ajaxian? I’m not even sure why you’re using it during regular browsing, in my experience it just slows things down. I keep it disabled and only turn it on when I explicitly need it.
Elad, yes, that works. It doesn’t change the example posted here though :)
Interesting. jQuery does the following since the early days:
if ( !window.XMLHttpRequest )XMLHttpRequest = function(){
return new ActiveXObject("Microsoft.XMLHTTP");
};
;) Klaus
This still does detection on every request. Why not branch at load?