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: ajax, javascript | Category: Web
一般预加载图片,通过 new image(url) 来实现的。用xhr有点南辕北辙
March 31, 2009 8:53 AM