jQuery中ajax方法的改进

前些日子在做一个用 ajax 异步加载文件的预加载组件,系统以 jQuery 为基础,将页面要用到的组件,例如静态js,css,html 等文本类型的文件和图片、flash 等二进制类型的数据,加载到浏览器缓存中。这里遇到一个问题。


在 jQuery 中的 ajax 异步请求方法返回的时候,会去解析返回的值,企图将返回值解析为文本,例如 responseXML,或者 responseText 。如果请求的数据为二进制数据(例如图片),jQuery 就会报 parsererror 的错。其实这也不算是 jQuery 的 Bug,因为 XMLHTTPRequest 的 API 原本就是为了处理纯文本形式的数据,但纯文本数据本身也是二进制的,XMLHTTPRequest 是可以请求二进制数据的。

我在 jquery.js 中作了一点点的修改,让它支持请求非文本的二进制数据。

jquery.js 中的 ajax 明确支持的 MIME 类型在 ajaxSettings 属性中定义为(第2558行):

2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
    ajaxSettings: {
        url: location.href,
        global: true,
        type: "GET",
        timeout: 0,
        contentType: "application/x-www-form-urlencoded",
        processData: true,
        async: true,
        data: null,
        username: null,
        password: null,
        accepts: {
            xml: "application/xml, text/xml",
            html: "text/html",
            script: "text/javascript, application/javascript",
            json: "application/json, text/javascript",
            text: "text/plain",
            _default: "*/*"
        }
    },

jquery.js(1.2.6)中报错的位置是在第2878行的 httpData 函数中:

2878
2879
2880
2881
2882
2883
2884
2885
    httpData: function( xhr, type, filter ) {
        var ct = xhr.getResponseHeader("content-type"),
            xml = type == "xml" || !type && ct && ct.indexOf("xml") >= 0,
            data = xml ? xhr.responseXML : xhr.responseText;
 
        if ( xml && data.documentElement.tagName == "parsererror" )
            throw "parsererror";
        //......

可以看出,这里的 xml 变量不管是 true 还是 false,data 都会去获取 xhr.responseXML 或者 xhr.responseText,也就是去解析返回的内容。很明显,如果返回的是非文本的数据,这里就会抛出 parsererror 的异常。修改后:

2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
    httpData: function( xhr, type, filter ) {
        var ct = xhr.getResponseHeader("content-type");
        var xml = type == "xml" || !type && ct && ct.indexOf("xml") >= 0;
 
        // if response is binary data, like image,application, return null
        // modified by belltoy at 2008-12-04
        if((ct.indexOf("javascript") < 0 && ct.indexOf("text") < 0 && ct.indexOf("xml") < 0 && ct.indexOf("json") < 0) 
           && (ct.indexOf("image") >=0 || ct.indexOf("application") >=0)) {
            return null;
        }
 
        var data = xml ? xhr.responseXML : xhr.responseText;
        //......

即如果返回数据不是文本类型,则直接返回 null,因为我只要下载二进制文件到本地浏览器缓存,而不需要在 javascript 里处理非文本类型的数据。这样修改增加就避免了 parsererror 异常。

补充:一般我们做大访问量网站的时候,会把静态的组件分离出来放到一个静态 HTTP 服务器上,以减轻主服务器的负载。这时候做预加载,就需要处理同源策略的问题。参考文章:《Javascript跨域和Ajax跨域解决方案》

相关文章

Tags: , | Category: Web

By belltoy On December 27, 2008 11:45 PM | delicious 收藏 | Twitter 分享

一条评论

  1. xlambda 说:

    一般预加载图片,通过 new image(url) 来实现的。用xhr有点南辕北辙

添加评论

(若看不到验证码,请点击此处。)