高性能JavsScript异步AJAX和XML
"在原始的网站开发中,每次HTTP请求都会下载整个页面,在浏览器端进行渲染,每次的请求都是基于页面的,随着对用户体验的不断关注,近年来AJAX技术是提高WEB性能的主要技术,因为它可以异步发起细粒度的请求,局部更新页面,不会导致全页面重新渲染,优点是不容置疑的,较少流量的同时可减少浏览器对页面的重排版和元素的重新渲染,可显著提高用户体验。
关于XMLHttpRequest对象
目前最常用的方法中,XMLHttpRequest(简称:XHR)对象用于异步收发数据,几乎所有的浏览器都能够支持XHR对象,而且能够更精确控制发送和接收数据的格式,这意味XHR不但可以发送接受消息本身,它还可以改变和查询HTTP请求头,虽然AJAX可在一定程度上提高性能和用户体验,但浏览器为了安全,都不允许XHR跨域发送和接受数据。
<span style=background: white; color: blue;><<span style=background: white; color: maroon;>script <span style=background: white; color: red;>type<span style=background: white; color: blue;>=text/javascript> var <span style=background: white; color: black;>url = <span style=background: white; color: #a31515;>'http://www.xcode.me/mobileapi.aspx'<span style=background: white; color: black;>; <span style=background: white; color: blue;>var <span style=background: white; color: black;>xhr = <span style=background: white; color: blue;>new <span style=background: white; color: black;>XMLHttpRequest(); xhr.onreadystatechange = <span style=background: white; color: blue;>function <span style=background: white; color: black;>() { <span style=background: white; color: blue;>if <span style=background: white; color: black;>(req.readyState === 4) { <span style=background: white; color: blue;>var <span style=background: white; color: black;>responseHeaders = req.getAllResponseHeaders(); <span style=background: white; color: blue;>var <span style=background: white; color: black;>data = req.responseText; } } xhr.open(<span style=background: white; color: #a31515;>'GET'<span style=background: white; color: black;>, url, <span style=background: white; color: blue;>true<span style=background: white; color: black;>); xhr.setRequestHeader(<span style=background: white; color: #a31515;>Content-type<span style=background: white; color: black;>, <span style=background: white; color: #a31515;>application/json<span style=background: white; color: black;>); xhr.send(<span style=background: white; color: blue;>null<span style=background: white; color: black;>); <span style=background: white; color: blue;></<span style=background: white; color: maroon;>script<span style=background: white; color: blue;>>
上面的代码,首先创建一个Ajax对象XHR,设置请求头尾JSON格式,并向指定的URL发送GET请求,等待返回数据,当readyState的值为4时,表示请求完成,可进行数据处理,readyState的值为3时表示正在与服务器端传输数据,此时接受到的可能只是部分报文。
当使用XHR请求数据,可用POST方式或者GET方式,如果只是查询数据,零度推荐您使用GET,因为GET天生具有缓存性质,多次GET同一个URL可能被浏览器缓存,可提高性能,只有当URL长度超过浏览器限制的字符数时,才考虑使用POST,因为URL过长这将导致浏览器截断。
动态脚本标签插入
使用动态脚本标签插入技术,克服了XHR无法跨域访问的缺点,它可以允许不同域之间的请求,实现原理是:通过JavaScript创建一个script标签,并将script标签的src设置为指定的URL,这将导致浏览器会向URL发送请求并下载内容,最后将脚本内容插入到script标签中。
<span style=background: white; color: blue;><<span style=background: white; color: maroon;>script <span style=background: white; color: red;>type<span style=background: white; color: blue;>=text/javascript> var <span style=background: white; color: black;>scriptElement = document.createElement(<span style=background: white; color: #a31515;>'script'<span style=background: white; color: black;>); scriptElement.src = <span style=background: white; color: #a31515;>'http://www.xcode.me/script/public.js'<span style=background: white; color: black;>; document.getElementsByTagName(<span style=background: white; color: #a31515;>'head'<span style=background: white; color: black;>)[0].appendChild(scriptElement); <span style=background: white; color: blue;></<span style=background: white; color: maroon;>script<span style=background: white; color: blue;>>
动态脚本插入与XHR相比,动态脚本插入具有更小的控制权,你不能设置请求头,而且只支持GET请求,无法设置请求超时或者重试,script标签的下载具有阻塞性。另外,由于创建script标签,所以插入到标签之中的内容必须是可被浏览器执行的JavaScript代码,否则会出现语法错误。
<span style=background: white; color: blue;><<span style=background: white; color: maroon;>script <span style=background: white; color: red;>type<span style=background: white; color: blue;>=text/javascript> var <span style=background: white; color: black;>scriptElement = document.createElement(<span style=background: white; color: #a31515;>'script'<span style=background: white; color: black;>); scriptElement.src = <span style=background: white; color: #a31515;>'http://www.xcode.me/javascript/test.js'<span style=background: white; color: black;>; document.getElementsByTagName(<span style=background: white; color: #a31515;>'head'<span style=background: white; color: black;>)[0].appendChild(scriptElement); <span style=background: white; color: blue;>function <span style=background: white; color: black;>jsonCallback(jsonString) { <span style=background: white; color: green;>//这里是数据处理代码。 <span style=background: white; color: black;>} <span style=background: white; color: blue;></<span style=background: white; color: maroon;>script<span style=background: white; color: blue;>>
文件test.js中的代码如下所示:
<span style=background: white; color: black;>jsonCallback({ <span style=background: white; color: #a31515;>id<span style=background: white; color: black;>: <span style=background: white; color: #a31515;>001<span style=background: white; color: black;>, <span style=background: white; color: #a31515;>name<span style=background: white; color: black;>: <span style=background: white; color: #a31515;>xcode<span style=background: white; color: black;>, <span style=background: white; color: #a31515;>site<span style=background: white; color: black;>: <span style=background: white; color: #a31515;>零度 <span style=background: white; color: black;>});
上面的例子,首先创建一个script标签,然后设置scr地址为test.js,然后将script加入到head标签中,浏览器会自动下载test.js文件,然后将文件内容插入到script标签中,会执行jsonCallback方法,并将JSON传递参数传递,这样就形成了异步请求并执行代码。
使用图片进行数据发送而不接收
使用图片发送数据,这种技术与动态脚本插入很类似,它的原理是用JavaScript创建image对象,然后设置image的src属性,让浏览器想src属性所制定的地址发送GET请求,即可完成一次数据发送,由于响应空内容,所以界面不显示图片,只完成请求,当然您也可以绑定image的load事件捕捉请求完成事件,如果您只关心图片发送到服务端,那么iamge请求是发送数据是一个不错的方案。
数据格式的传输
数据格式有很多一个JSON、字符串或者XML,我们选择格式时,主要指标包括传输速度、解析速度和在服务端构造格式的难易程度,没有任何一种格式是绝对最好的,我们应该结合场景来分析具体问题。
当AJAX开始流行的时候,最标准的方式就是XML数据格式,那时候,还是没有JSON的概念,XML具有很好的兼容性和严格的格式验证,XML是W3C标准,JSON还没有规范的标准,所以XML作为当年最普遍的传输格式。
<span style=background: white; color: blue;>xml version=""1.0"" encoding=""utf-8""?> <<span style=background: white; color: #a31515;>urlset<span style=background: white; color: blue;>> <<span style=background: white; color: #a31515;>url<span style=background: white; color: blue;>> <<span style=background: white; color: #a31515;>loc<span style=background: white; color: blue;>><span style=background: white; color: black;>http://www.xcode.me<span style=background: white; color: blue;></<span style=background: white; color: #a31515;>loc<span style=background: white; color: blue;>> <<span style=background: white; color: #a31515;>changefreq<span style=background: white; color: blue;>><span style=background: white; color: black;>daily<span style=background: white; color: blue;></<span style=background: white; color: #a31515;>changefreq<span style=background: white; color: blue;>> <<span style=background: white; color: #a31515;>priority<span style=background: white; color: blue;>><span style=background: white; color: black;>1.0<span style=background: white; color: blue;></<span style=background: white; color: #a31515;>priority<span style=background: white; color: blue;>> </<span style=background: white; color: #a31515;>url<span style=background: white; color: blue;>> <<span style=background: white; color: #a31515;>url<span style=background: white; color: blue;>> <<span style=background: white; color: #a31515;>loc<span style=background: white; color: blue;>><span style=background: white; color: black;>http://www.xcode.me/video<span style=background: white; color: blue;></<span style=background: white; color: #a31515;>loc<span style=background: white; color: blue;>> <<span style=background: white; color: #a31515;>changefreq<span style=background: white; color: blue;>><span style=background: white; color: black;>weekly<span style=background: white; color: blue;></<span style=background: white; color: #a31515;>changefreq<span style=background: white; color: blue;>> <<span style=background: white; color: #a31515;>priority<span style=background: white; color: blue;>><span style=background: white; color: black;>0.6<span style=background: white; color: blue;></<span style=background: white; color: #a31515;>priority<span style=background: white; color: blue;>> </<span style=background: white; color: #a31515;>url<span style=background: white; color: blue;>> <<span style=background: white; color: #a31515;>url<span style=background: white; color: blue;>> <<span style=background: white; color: #a31515;>loc<span style=background: white; color: blue;>><span style=background: white; color: black;>http://www.xcode.me/tool<span style=background: white; color: blue;></<span style=background: white; color: #a31515;>loc<span style=background: white; color: blue;>> <<span style=background: white; color: #a31515;>changefreq<span style=background: white; color: blue;>><span style=background: white; color: black;>weekly<span style=background: white; color: blue;></<span style=background: white; color: #a31515;>changefreq<span style=background: white; color: blue;>> <<span style=background: white; color: #a31515;>priority<span style=background: white; color: blue;>><span style=background: white; color: black;>0.6<span style=background: white; color: blue;></<span style=background: white; color: #a31515;>priority<span style=background: white; color: blue;>> </<span style=background: white; color: #a31515;>url<span style=background: white; color: blue;>> </<span style=background: white; color: #a31515;>urlset<span style=background: white; color: blue;>>
上面是一段标准的XML文件,我们发现元素具有开始和结束标签,在一定程度上具有冗余性,在JavaScript中解析XML是对开发人员不来说是相当费力的,由于要遍历DOM元素,所以性能也会有所影响,最好的做法是将节点全部转换成属性,然后使用getElementsByTagName方法查找文档节点后,解析元素属性,这样可以减少遍历DOM对象的次数,可在一定程度上提高性能。
随着web技术的不断发展,一种新的JSON格式问世,JSON 具有下载最快和解析时间短的特点,可以用下面的代码表示上面的XML数据。
<span style=background: white; color: black;>{ urlset: { url: [ { loc: <span style=background: white; color: #a31515;>http://www.xcode.me<span style=background: white; color: black;>, changefreq: <span style=background: white; color: #a31515;>daily<span style=background: white; color: black;>, priority: <span style=background: white; color: #a31515;>1.0 <span style=background: white; color: black;>}, { loc: <span style=background: white; color: #a31515;>http://www.xcode.me/video<span style=background: white; color: black;>, changefreq: <span style=background: white; color: #a31515;>weekly<span style=background: white; color: black;>, priority: <span style=background: white; color: #a31515;>0.6 <span style=background: white; color: black;>}, { loc: <span style=background: white; color: #a31515;>http://www.xcode.me/tool<span style=background: white; color: black;>, changefreq: <span style=background: white; color: #a31515;>weekly<span style=background: white; color: black;>, priority: <span style=background: white; color: #a31515;>0.6 <span style=background: white; color: black;>} ] } }
总的来说,轻量级的JSON格式更好,因为几乎它越来越流行,而且解析它很容易,而且被广泛使用。
除了以上所说的两种格式,JSONP和自定义格式也经常被使用,JSONP类似于脚本动态注入,服务器端返回一个方法调用并传入JSON对象,在方法回调中直接使用,自定义个是是指自己定义的格式,没有现成的解析框架可供选择,需要自行编写代码解析。
缓存数据提高性能
数据格式被选定后,基于性能的考虑主要是传输和缓存上,任何服务端语言都可设置HTTP请求头,可更改报文在客户端浏览器的缓存时间,如果你希望AJAX返回的数据能够被浏览器所缓存,那么必须采用GET请求而非POST请求,HTTP协议中Expires头通过指定一个GMT时间告诉浏览器报文要缓存的时间。"