Friday, April 18th, 2008
100 Line Ajax Wrapper
>Kris Zyp gives us a glimpse at a potential future with his 100 line Ajax wrapper that tries to do the right thing cross browser for the various cross-domain models:
With IE8’s new XDomainRequest feature, a new API is added for cross-site requests, instead of using the W3C cross-site access proposal. Just for fun, I thought I would provide a little glimpse of what the classic Ajax request wrapper function may look like for the next era of web developers. Just a few simple calls to XMLHttpRequest would be way too easy, so instead we get do this:
-
-
function doRequest(method,url,async,onLoad,onProgress) {
-
var xhr;
-
if ((onProgress || isXDomainUrl(url)) && window.XDomainRequest) {
-
// if it is x-domain or streaming/incremental updates are needed we will use IE's XDomainRequest for IE
-
// streaming/interactive mode is broken in IE's XHR, but for some reason works in XDR (with onprogress), so we will
-
// need to use XDR if incremental updates are necessary
-
// see bug https://connect.microsoft.com/IE/feedback/ViewFeedback.aspx?FeedbackID=334813
-
if (url.match(/^https:/) && !onProgress) {
-
// XDR doesn’t work for secure https communication
-
// see bug https://connect.microsoft.com/IE/feedback/ViewFeedback.aspx?FeedbackID=333380
-
loadUsingScriptTag(url); // script tag insertion can be more secure than XDR
-
// in some situations because it supports https
-
return;
-
}
-
xhr = new XDomainRequest;
-
// relative paths don’t work in XDomainRequest, see bug https://connect.microsoft.com/IE/feedback/ViewFeedback.aspx?FeedbackID=333275
-
if (!url.match(/^http:/)) { // test to see if it is an absolute url
-
url = absoluteUrl(location.href,url); // must have a function to turn it into an absolute url
-
}
-
if (!(method == “GET†|| method == “POSTâ€)) {
-
// XDomainRequest does not support methods besides GET and POST
-
// see bug https://connect.microsoft.com/IE/feedback/ViewFeedback.aspx?FeedbackID=334809
-
// We will try to add the method as a parameter and hope the server will understand… good luck :/
-
url += “&method=†+ method;
-
method = “POSTâ€;
-
}
-
function xdrLoad() {
-
if (xhr.contentType.match(//xml/)){
-
// there is no responseXML in XDomainRequest, so we have to create it manually
-
dom.async = false;
-
dom.loadXML(xhr.responseText,200);
-
onLoad(dom);
-
}
-
else {
-
onLoad(xhr.responseText,200); // we will assume that the status code is 200, XDomainRequest rejects all other successful status codes
-
// see bug https://connect.microsoft.com/IE/feedback/ViewFeedback.aspx?FeedbackID=334804
-
}
-
}
-
if (async === false) {
-
// XDomainRequest does not support synchronous requests
-
// see bug https://connect.microsoft.com/IE/feedback/ViewFeedback.aspx?FeedbackID=336031
-
// so we will try to block execution on our own (which is not really possible in any reasonable manner)
-
var loaded;
-
xhr.onload = function() {
-
loaded = true;
-
xdrLoad();
-
}
-
xhr.open(method,url);
-
xhr.send(null);
-
while(!loaded) { // try to block until the response is received
-
// I am sure the user won’t mind just clicking OK so we can block execution
-
alert(â€Waiting for the response, please click OK because it probably is here nowâ€);
-
}
-
return;
-
}
-
xhr.onload = xdrLoad;
-
xhr.open(method,url);
-
xhr.onprogress = onProgress;
-
}
-
}
-
// we will mercifully skip all the branches for ActiveXObject(â€Microsoft.XMLHTTPâ€) to accomodate IE6 and lower
-
else {
-
xhr = new XMLHttpRequest; // use the standard XHR for same origin and browsers that implement cross-site
-
// W3C requests and streaming
-
xhr.open(method,url,async);
-
xhr.onreadystatechange = function() {
-
if (xhr.readyState == 3) // interactive mode
-
onProgress(xhr.responseText);
-
if (xhr.readyState == 4) // finished
-
onLoad(xhr.responseText,xhr.status);
-
}
-
}
-
xhr.send(null); // finally send the request whether it be XDR or XHR
-
-
// and supporting functions
-
function absoluteUrl : function(baseUrl, relativeUrl) {
-
// This takes a base url and a relative url and resolves the target url.
-
// For example:
-
// resolveUrl(â€http://www.domain.com/path1/path2″,â€../path3″) ->â€http://www.domain.com/path1/path3″
-
//
-
if (relativeUrl.match(/w+:///))
-
return relativeUrl;
-
if (relativeUrl.charAt(0)==’/') {
-
baseUrl = baseUrl.match(/.*//[^/]+/)
-
return (baseUrl ? baseUrl[0] : â€) + relativeUrl;
-
}
-
//TODO: handle protocol relative urls: ://www.domain.com
-
baseUrl = baseUrl.substring(0,baseUrl.length - baseUrl.match(/[^/]*$/)[0].length);// clean off the trailing path
-
if (relativeUrl == ‘.’)
-
return baseUrl;
-
while (relativeUrl.substring(0,3) == ‘../’) {
-
baseUrl = baseUrl.substring(0,baseUrl.length - baseUrl.match(/[^/]*/$/)[0].length);
-
relativeUrl = relativeUrl.substring(3);
-
}
-
return baseUrl + relativeUrl;
-
}
-
function loadUsingScriptTag(url) {
-
… do JSONP here if we want
-
}
-
}
I think that says.... please just implement the standard IE team! :)
Related Content:











“With IE8’s new XDomainRequest feature, a new API is added for cross-site requests, instead of using the W3C cross-site access proposal”
Gee, I see they are back to avoiding standards. They never learn… :(
Oh no, Steve — they learned. They learned a long time ago how to Embrace, Extend, and Extinguish.
But, seriously, let them do what they want — we’ll make all wrappers cross-browser like we’ve been doing, and then Microsoft will just have to put up with their scripts running as slow as everyone else’s.