在使用应用的时候,特别是独占式的应用,用户会持续地和应用进行交互,所以基于 Web的开发,网络延迟是一个很重要的因素,传统的web应用依赖于整个页面的重新加载。每一次发到服务器的调用都会打断用户的使用。这便需要异步加载数据来实现。
最早提供这种后台通信能力是使用 IFrame ,后来,XMLHttpRequest对象提供了更清晰和强大的功能。我们先来看一下这2个技术。
IFrame : I 字母代表的是“inline”,意味着它是另外一个文档布局的一部分。一个IFrame表现为DOM的一个元素,只要页面可见,我们就可以改变它的大小、移动、或者将它完全隐藏。关键是,我们使得了IFrame不可见,从表面来看,在不可见的元素里加载一些我们即将用到的数据,这并不影响用户当前的工作,这使得以后台方式获得数据成了可能。从此我们有了一种与服务器进行异步通讯的机制。虽然这只不过是一种 Hack 式的临时解决方案。
和其他的DOM元素一样,IFrame可以在HTML中声明,也可以使用 document.createElement()方法来创建。自然也可以通过getElementById()来获取它的引用。
<
html xmlns
=
"
http://www.w3.org/1999/xhtml
"
>
<
head runat
=
"
server
"
>
<
title
>
无标题页
</
title
>
<
script type
=
"
text/javascript
"
>
window.onload
=
function
()
...
{ var iframe = document.getElementById( " dataFeed " ); var src = " datafeeds/mydata.xml " ; loadDataAsynchronously(iframe,src); }
function
loadDataAsynchronously(ifrmae,src)
...
{ // ...............以后再说这里的功能。 }
</
script
>
</
head
>
<
body
>
<
form id
=
"
form1
"
runat
=
"
server
"
>
<
div
>
<
iframe id
=
"
dataFeed
"
style
=
"
width:0px; height:0px;
"
></
iframe
>
</
div
>
</
form
>
</
body
>
</
html
>
上面我们是通过前台的声明来创建了 IFrame ,当然也可以:
XMLDocument和XMLHttpRequest对象:
XmLDocument和XMLHttpRequest并不是DOM的标准扩展,只是碰巧得到了多数浏览器的支持,它们的设计目的很明确,就是用来以后台方式获得数据 。两者都是源自微软私有的ActiveX组件,可以在浏览器中作为JavaScript对象来访问。两者对象执行的功能很相似,只是 XMLHttpRequest对象可以更加精细地对请求进行控制,我们主要使用XMLHttpRequest。这里先来介绍一下 XMLDocument。
<
script type
=
"
text/javascript
"
>
function
getXMLDocument()
//
用来创建XMLDocument对象
...
{ var xDoc = null ; if (document.implementation && document.implementation.createDocument) ... { xDoc = document.implementation.createDocument( "" , "" , null ); // 首先检查文档是否支持创建一个原生的XMLDocument对象所需的implementation属性。 // implementation中文意思是“执行”,名词。如果支持则创建。 } else // 如果没有找到implementation属性,则测试浏览器是否支持ActiveX对象。 ... { if ( typeof ActiveXObject != " undefined " ) ... { var msXmlAx = null ; try ... { msXmlAx = new ActiveXObject( " Msxml2.DOMDocument " ); // 如果支持ActiveX ,则先尝试第二版MSXML库来创建该对象。 } catch (e) ... { msXmlAx = new ActiveXObject( " Msxml.DOMDocument " ); // 如果不支持新版MSXML库,则使用旧版创建该对象。 } xDoc= msXmlAx; } } if (xDoc == null || typeof xDoc.load == " undefined " ) ... { xDoc = null ; // 如果上面两种方式都不支持,则简单地返回空的XMLDocument对象。我们将在后面详细讲解怎么才能更加优雅地处理这种情况。 } return xDoc; }
</
script
>
在上述函数getXMLDocument()中,我们并没有试图去猜测浏览器的版本,而是直接检测特定的对象是否可用,这种方法也称作对象检测(object detection) 。
下面我们来看 XMLHttpRequest对象:
同样,首先来创建XMLHttpRequest对象,使用对象检测,检测是否支持原生的XMLHttpRequest对象,如果不支持,则检测是否支持 ActiveX 对象,如果两个都不支持,则简单地返回null;
<
html xmlns
=
"
http://www.w3.org/1999/xhtml
"
>
<
head runat
=
"
server
"
>
<
title
>
无标题页
</
title
>
<
script type
=
"
text/javascript
"
>
function
getXMLHttpRequest()
...
{ var xRequest = null ; if (window.XMLHttpRequest) ... { xRequest = new XMLHttpRequest(); } else if ( typeof ActiveXObject != " undefined " ) ... { xRequest = new ActiveXObject( " Microsoft.XMLHTTP " ); } return xRequest; }
</
script
>
</
head
>
<
body
>
<
form id
=
"
form1
"
runat
=
"
server
"
>
<
div
>
</
div
>
</
form
>
</
body
>
</
html
>
由上述代码,如果浏览器支持其中的一种,则我们就成功的创建了XMLHttpRequest对象。既然创建了对象,我们就要利用它,现在我们使用已经创建的XMLHttpRequest对象来向服务器发送数据。
通过XMLHttpRequest向服务器发送数据是一件很直接的事情,我们所要做的所有事情就是给它传递一个服务器页面的URL,这个页面将生成数据,如下:
<
html xmlns
=
"
http://www.w3.org/1999/xhtml
"
>
<
head runat
=
"
server
"
>
<
title
>
无标题页
</
title
>
<
script type
=
"
text/javascript
"
>
function
getXMLHttpRequest()
...
{ var xRequest = null ; if (window.XMLHttpRequest) ... { xRequest = new XMLHttpRequest(); } else if ( typeof ActiveXObject != " undefined " ) ... { xRequest = new ActiveXObject( " Microsoft.XMLHTTP " ); } return xRequest; }
function
sendRequest(url,params,HttpMethod)
...
{ if ( ! HttpMethod) ... { HttpMethod = " POST " ; } var req = getXMLHttpRequest(); if (req) ... { req.open(HttpMethod,url, true ); req.setRequestHeader( " Content-Type " , " application/x-www-form-urlencoded " ); req.send(params); } }
</
script
>
</
head
>
<
body
>
<
form id
=
"
form1
"
runat
=
"
server
"
>
<
div
>
</
div
>
</
form
>
</
body
>
</
html
>
通过上面代码,我们成功地向服务器发送了一个请求,一个HTTP请求主要由 首部信息 和可能包含一些数据或参数的主体部分组成。响应则通常包括返回页面的HTML标记。这里我们将HTTP方法设置为POST请求方法。
简单说一下,HTTP方法有 "GET"用来获取文档;"POST"用来提交HTML表单;除外W3C还规约了一些其他的通用方法, "HEAD"用来获取一个文件的首部信息;"PUT"用来向服务器上传文档;"DELETE"用来删除服务器上的文档。
sendRequest()方法中包含的第二个和第三个参数都是可选参数,大部分情况都用不上。默认使用POST方法来获取资源,在请求的主体部分不需要传递任何参数。起上述代码对请求进行设置后,会立即将控制权返还给我我们,与此同时网络和服务器则正忙着他们自己的任务。这对于提高响应能力很有好处,但是我们怎样才能知道请求完成了呢?下面我们来讲解下。
使用回调函数监视请求:
处理异步通信的第二部分是在代码中设置一个入口,以便在调用结束的时候,可以获取结果,这通常是通过分配一个回调函数来实现的。也就是说,在未来某个不确定的时刻,当结果返回的时候,将会执行这一段代码。象我们平时见到的,window.onload函数以及UI控件上的onkeypress、onmouseover等都是回调函数。
下面我们来看下一个简单的回调处理函数的代码:
<
html xmlns
=
"
http://www.w3.org/1999/xhtml
"
>
<
head runat
=
"
server
"
>
<
title
>
无标题页
</
title
>
<
script type
=
"
text/javascript
"
>
var
READY_STATE_UNINITIALIZED
=
0
;
//
未初始化状态
var
READY_STATE_LOADING
=
1
;
//
正在载如状态
var
READY_STATE_LOADED
=
2
;
//
已载入状态标志
var
READY_STATE_INTERACTIVE
=
3
;
//
交互状态
var
READY_STATE_COMPLETE
=
4
;
//
完成
var
req;
function
getXMLHttpRequest()
...
{ var xRequest = null ; if (window.XMLHttpRequest) ... { xRequest = new XMLHttpRequest(); } else if ( typeof ActiveXObject != " undefined " ) ... { xRequest = new ActiveXObject( " Microsoft.XMLHTTP " ); } return xRequest; }
function
sendRequest(url,params,HttpMethod)
...
{ if ( ! HttpMethod) ... { HttpMethod = " POST " ; // 设置数据发送模式为POST } req= getXMLHttpRequest(); // 创建XMLHttpRequest实例 if (req) ... { req.onreadystatechange = onReadyStateChange; // 当载入的状态变化,交给onReadyStateChange来处理 req.open(HttpMethod,url, true ); req.setRequestHeader( " Content-Type " , " application/x-www-form-urlencoded " ); req.send(params); } }
function
onReadyStateChange()
...
{ var ready = req.readyState; // 获取XMLHttpRequest对象实例当前的状态 var data = null ; if (ready == READY_STATE_COMPLETE) ... { data = req.responseText; // 如果请求发送已经完成,则将请求的数据内容保存在data变量中 } else ... { data = " Loading...+[ " + ready + " ] " ; // 如果请求发送尚未完成,则显示当前所处的状态 } // .....do sth. with the data }
</
script
>
</
head
>
<
body
>
<
form id
=
"
form1
"
runat
=
"
server
"
>
<
div
>
</
div
>
</
form
>
</
body
>
</
html
>