Ajax是高性能JavaScript的基石,是提升网站可用性的最大改进之一。利用Ajax可以在网站大量使用异步请求,解决需要加载太多资源的问题。Ajax可以通过延迟下载大量资源使页面加载更快,还可以通过在客户端和服务器之间异步传送数据避免页面集体加载。Ajax还用于在一次HTTP请求中获取整个页面的资源,通过选择正确的传输技术和最有效的数据格式,可以显著改善用户与网站之间的互动。
作为数据格式,纯文本和HTML是被高度限制的,但它们可节省客户端的CPU周期。XML被广泛应用和普遍支持,但它非常冗长且解析缓慢。JSON是轻量级的,解析迅速,交互性与XML相当。字符分隔的自定义格式是非常轻量级的,在大量数据集解析时速度最快,但需要编写额外的程序在服务器端构造格式,并且需要在客户端解析。
XHR(XMLHttpRequest)将所有传入数据视为一个字符串,这种用法方便控制,让使用更具灵活性,当然它也有缺点,可能会降低解析速度。另外,XHR虽然允许跨域请求和本地运行,但是这个接口不够安全,且不能读取信息头或响应报文代码。大部分XHR可减少请求的数量,可在一次响应中处理不同的文件类型,尽管它不能缓存收到的响应报文。XHR也可用POST方法发送大量数据。
建议137:使用隐藏框架实现异步通信
隐藏框架只是异步交互的一个载体,它仅负责信息的传输,而交互的核心是一种信息处理机制,这种处理机制就是回调函数。所谓回调函数,就是客户端页面中的一个普通函数,不过该函数在服务器端被调用,并负责处理服务器端响应的信息。
下面示例初步展现了异步信息交互中请求和响应的完整过程,其中回调函数的处理是整个流程的焦点。
第1步,构建一个框架集(回调处理.htm),如下:
<html>
<head>
<title>使用隐藏框架与服务器进行异步通信</title>
</head>
<frameset rows=/"*,0/">
<frame src=/"回调处理_main.htm/"name=/"main/"/>
<frame src=/"回调处理_black.htm/"name=/"serve/"/>
</frameset>
<noframes>你的浏览器不支持框架集,请升级浏览器版本!</noframes>
</html>
这个框架集由上下两个框架组成,框架2(下框架)高度为0。建议尽量不要设置高为0像素,因为在一些老版本的浏览器中依然会显示高度为0的框架。这两个框架的分工如下:
❑框架1(main),负责与用户进行信息交互。
❑框架2(serve),负责与服务器进行信息交互。
由于老版本浏览器可能不支持框架技术,所以应使用<noframes>来兼容它们,使设计显得更友好。
第2步,在默认状态下,框架集中的框架2加载一个空白页面(回调处理_black.htm),框架1加载与客户进行交互的页面(回调处理_main.htm)。
框架1中主要包含两个函数:一个是响应用户操作的回调函数,另一个是向服务器发送请求的事件处理函数。具体代码如下:
<html>
<head>
<title>与客户交互页面</title>
<script language=/"javascript/"type=/"text/javascript/">
function request{//向服务器发送请求的异步请求函数
var user=document.getElementById(/"user/");//获取输入的用户名
var pass=document.getElementById(/"pass/");//获取输入密码
var s=/"user=/"+user.value+/"&pass=/"+pass.value;//构造查询字符串
parent.frames[1].location.href=/"回调处理_serve.htm?/"+s;/*为框架集中的框架2加载服务器端请求文件,并附加查询字符串,传送客户端信息,以实现异步信息的双向交互*/
}
function callback(b,n){//异步交互的回调函数
if(b){//如果参数b为真,说明输入信息正确
var e=document.getElementsByTagName(/"body/")[0];/*获取框架1中body元素的引用指针,以实现向其中插入信息*/
e.innerHTML=/"<h1>/"+n+/"</h1><p>您好,欢迎登录站点</p>/";/*在交互页面中插入新的交互信息*/
}
else{//如果参数b为假,说明输入信息不正确
alert(/"你输入的用户名或密码有误,请重新输入/");//提示重新输入信息
var user=parent.frames[0].document.getElementById(/"user/");/*获取框架1中的用户名文本框*/
var pass=parent.frames[0].document.getElementById(/"pass/");/*获取框架1中的密码文本框*/
user.;
//清空用户名文本框中的值
pass.;
//清空密码文本框中的值
}}
window.onload=function{//页面初始化处理函数
var b=document.getElementById(/"submit/");//获取【提交】按钮b.onclick=request;//绑定鼠标单击事件处理函数
}
</script>
</head><body>
<h1>用户登录</h1>
用户名:<input name=/"/"id=/"user/"type=/"text/"><br/>
密 码:<input name=/"/"id=/"pass/"type=/"password/"><br/>
<input name=/"submit/"type=/"button/"id=/"submit/"/></body>
</html>
由于回调函数是在服务器端文件中被调用的,因此对象作用域的范围就发生了变化,此时应该指明它的框架集和框架名或序号,否则在页面操作中会找不到指定的元素。
第3步,在服务器端的文件中设计响应处理函数,该函数将分解HTTP传递过来的URL信息,获取查询字符串,并且根据查询字符串中用户名和密码来判断当前输入的信息是否正确,进而决定具体响应的信息。
<html><head>
<title>服务器端响应和处理页面</title>
<script language=/"javascript/"type=/"text/javascript/">window.onload=function{
//服务器响应处理函数,当该页面被请求加载时触发
var query=location.search.substring(1);//获取HTTP请求的URL中所包含的查询字符串var a=query.split(/"&/");
//将查询字符串分离成数组
var o={};
//临时对象直接量
for(var i=0;i<a.length;i++){
//遍历查询字符串数组
var pos=a[i].indexOf(/"=/");
//找到等号的下标位置
if(pos==-1)continue;
//如果没有等号,则忽略
var name=a[i].substring(0,pos);
//获取等号前面的字符串
var value=a[i].substring(pos+1);
//获取等号后面的字符串
o[name]=unescape(value);
//把名-值对传递给对象
}
var n,b;
((o[/"user/"])&&o[/"user/"]==/"admin/")?(n=o[/"user/"]):(n=null);
/*如果用户
名存在,且等于/"admin/",则记录该信息,否则设置为null*/
((o[/"pass/"])&&o[/"pass/"]==/"123456/")?(b=true):(b=false);/*如果密码
存在,且等于/"123456/",则设置变量b为true,否则为false*/
parent.frames[0].callback(b,n);/*调用客户端框架集中框架1中的回调函数,并把处理的信
息传递给它*/
}
</script>
</head><body>
<h1>服务器端响应和处理页面</h1>
</body></html>
在实际开发中,服务器端文件一般为动态服务器类型的文件,并且借助服务器端脚本来获取用户的信息,然后决定响应的内容,一般还会像查询数据库一样返回查询内容等。本示例以简化的形式演示这个异步通信的过程,因此没有采用服务器技术。预览框架集,在客户交互页面中输入用户的登录信息,在向服务器提交请求之后,服务器首先接收从客户端传递过来的信息并进行处理,然后调用客户端的回调函数把处理后的信息响应回去。