Ajax 简介
文章转载自Rob Larsen,文章原地址:Ajax 简介 主流 Web 编程模式的历史实践和当前实践在过去几年,JavaScript 已从让人事后才想起的偶然对象变成最重要的 Web 语言。如果要指出一个推动这项技术显著进步的因素,那就是基于 Ajax 的应用程序开发的出现。 简言之,Ajax 是一种开发技术和设计模式,支持网站或应用程序,使用实时数据更新界面,无需页面刷新。该功能创建了一种更为流畅且更具桌面风格的用户体验。 Ajax 简史Ajax 的发展历史类似于其他许多一夜成名的技术。尽管 Ajax 似乎不知从何而来,但实际上,它已经存在很长一段时间了。多年的努力使其遍布 Web,在 Ajax 旗帜的带领下创建工具和模式。纵观最初网络泡沫的 DHTML 时代,以及网络公司破产后的黑暗年代,世界各地的开发人员解禁了 JavaScript 的超能力,将这个崭新的、令人激动的应用程序模式引人 Web。 XMLHttpRequest最早最重要的 Ajax 谜题是 XMLHttpRequest (XHR) API。XHR 是一种用于在 Web 浏览器和 Web 服务器间传输数据消息的 JavaScript API。它支持浏览器使用 HTTP POST(将数据传到服务器)或 GET 请求(从后台服务器访问数据)。该 API 是大多数 Ajax 交互的核心,也是现代 Web 开发的一项基本技术。 先锋除了 Microsoft 之外,还有其他一些企业开始进军原型 Ajax 领域。许多企业都开始尝试使用这些技术,其中有两个特别值得一提 — 一个是因为它是一个有趣且经常引用的 Ajax 开发脚注,另一个是因为它是真正将这些技术大众化的 Internet 巨头。 OddpostOddpost 是 2002 年推出的基于 Web 的高级邮件客户端。它利用许多目前人们所熟知的模式。在设计和交互方面,人们会想起桌面邮件客户端。在系统内部,Oddpost 使用开发人员称为 DataPacks 的概念将小块数据从服务器传输到浏览器。这将带来一种全新体验。 Google Maps、Google Suggest、Gmail 以及一篇重要文章真正的变化开始于几年后的 Gmail、Google Suggest 和 Google Maps 服务。这三项 Ajax 技术的使用使得 Web 开发界沸腾起来。它的响应能力和交互性对公众而言是全新的。新的 Google 应用程序很快引起了轰动。
虽然这个技术说明从某种程度上讲有些过时了,但基本模式依然是完整的:HTML 和 CSS 呈现数据和样式,DOM 和相关方法支持页面实时更新,XHR 支持与服务器通信,JavaScript 安排整体显示。 库基于 Ajax 开发的一个关键驱动因素是几个全功能 JavaScript 库的演变和改进。除了经验丰富的 JavaScript 开发人员,很少有人能够真正理解 Ajax 底层技术。因此,即使在 DHTML 时代,虽然研究出了大部分浏览器交互和动画来应对琐碎的超额,但数量有限的几个经验丰富的 JavaScript 工程师导致基于 Ajax 的站点需求和人才(他们可以从零开始编写这样一个界面)供应之间的差距的进一步扩大。通过提供随时可用的交互和动画,减少跨浏览器差异和改进核心 JavaScript API 缺点的实现,Prototype、Dojo 和 jQuery 这类库有助于大规模地填补这一空白。 异步 JavaScript 以及更多 JavaScript(对象表示法)从原始 post 时代到现代,Ajax 领域的最大改变是引入了 JSON,JSON 是一种基于 JavaScript 的数据传输。提供更小的文件和更便利的原生 JavaScript 访问(与 XML 使用的笨重的基于 DOM 的方法和属性截然相反),JSON 很快就被开发人员用于进行数据传输。现在 JSON 已列入近期完成的 ECMAScript 规范的第 5 版。 JSON+Padding原始 JSON 提议的一个显著增强是 JSON+Padding (JSONP)。正如您所看到的,XMLHttpRequest 对象有一个严格的安全模型,只支持使用与请求页面相同的域名和协议进行通信。JSONP 在这个跨域限制上创建了一种更为灵活的方法,将 JSON 响应包装到一个用户定义或系统提供的回调函数中。将 JSON 脚本添加到文档之后,该方法将会提供即时数据访问。该模式现在很常见,对于许多较大的 Web 服务,可以采用该实践来支持混搭应用和其他内容联合。 XMLHttpRequest API 和特性尽管可以使用其他技术从服务器中返回数据,但是 XHR 仍然是大多数 Ajax 交互的核心。XHR 交互由两部分组成:请求和响应。下面我们将逐个介绍。 安全模型正如上面所提到的,原始 XMLHttpRequest 对象有一个严格的安全模型。这个同源策略只 允许使用与请求页面相同的主机、协议和端口进行通信。这意味着不同域(example.com 和 example2.com)、不同主机(my.example.com 和 www.example.com)、不同协议(http://example.com 和 https://example.com)之间的通信是禁止的,这会产生错误消息。 Origin: http://example.com
并将服务器配置为发送回一个匹配的 “Access-Control-Allow-Origin” 报头: Access-Control-Allow-Origin: :
http://example.com
现在,可以使用 XHR 对象跨域进行双向通信了。 请求请求端有 4 种方法:
响应响应也有几个属性和方法:
readyState实例化完成后,XMLHttpRequest 对象有 5 种状态,使用以下值表示:
一个通用 JavaScript 示例在我们进一步介绍流行库之前,先通过几个原始的 JavaScript 示例来了解正在运用的核心技术。以下所有示例均可下载(参见 下载 部分),而且可以在任何运行 PHP 的 Web 服务器上运行。所有示例都可以处理 清单 1 中的简单文档。 <!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Simple Ajax Example</title>
<meta name="author" content="Rob Larsen">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="stylesheet" href="_assets/css/style.css">
</head>
<body>
<div id="main">
<h1>Simple Ajax Example</h1>
<p><strong id="activate">Click here</strong>
and content will be appended after this paragraph</p>
</div>
<script src="_assets/js/ajax.js"></script>
</body>
</html>
清单 2 举例说明了一个简单 GET 请求,该请求将处理 responseXML。这是该技术发展早期的典型 Ajax 交互。它可以在所有现代浏览器以及 Internet Explorer 7 和 8 中运行。 /* Here's a basic Ajax function */
var ajax = function( opts ) {
/* We have an options argument. In addition,we want to have some smart defaults. */
opts = {
//Is it a Get or Post
type: opts.type || "POST",//What URL are we going to hit?
url: opts.url || "",//What do we do with the data
onSuccess: opts.onSuccess || function(){},//what kind of data do we expect?
data: opts.data || "xml"
};
//create a new XMLHttpRequest
var xhr = new XMLHttpRequest();
//Open the connection to the server
xhr.open(opts.type,opts.url,true);
/* When the ready state changes fire this function */
xhr.onreadystatechange = function(){
//readyState 4 is "done"
if ( xhr.readyState == 4 ) {
/* do some simple data processing There are two components to the returned object- responseXML and responseText. Depending on what we're doing we'll need one or the other. */
switch (opts.data){
case "json":
//json is text
opts.onSuccess(xhr.responseText);
break;
case "xml":
//XML retains the structure/DOM
//It's passed in whole.
opts.onSuccess(xhr.responseXML);
break;
default :
//Everything else will get TXT
opts.onSuccess(xhr.responseText);;
}
}
};
//close the connection
xhr.send(null);
}
//here's our simple function
var ajaxSample = function(e){
//Simple callback adds some text to the page
var callback = function( data ) {
document.getElementById("main").innerHTML +=
"<p>"
+data.getElementsByTagName("data")[0].getAttribute("value")
+"</p>";
}
//And here's our Ajax call
ajax({
type: "GET",url: "_assets/data/ajax-1.xml",onSuccess: callback,data : "xml"
})
//prevent the default action
e.preventDefault();
}
//Wire everything up
document.getElementById("activate").addEventListener("click",ajaxSample,false);
在 清单 3 中可以看到活动的原始 ActiveX 对象。如果没有本机实现,可以在不同版本的 Internet Explorer 中使用 Try… Catch 块来循环遍历对象的潜在引用。这个完整的跨浏览器实现与 Internet Explorer 是兼容的,甚至可以与古老的 Internet Explorer 5 兼容。 var ajax = function( opts ) {
opts = {
type: opts.type || "POST",url: opts.url || "",onSuccess: opts.onSuccess || function(){},data: opts.data || "xml"
};
/* Support for the original ActiveX object in older versions of Internet Explorer This works all the way back to IE5. */
if ( typeof XMLHttpRequest == "undefined" ) {
XMLHttpRequest = function () {
try {
return new ActiveXObject("Msxml2.XMLHTTP.6.0");
}
catch (e) {}
try {
return new ActiveXObject("Msxml2.XMLHTTP.3.0");
}
catch (e) {}
try {
return new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e) {}
throw new Error("No XMLHttpRequest.");
};
}
var xhr = new XMLHttpRequest();
xhr.open(opts.type,true);
xhr.onreadystatechange = function(){
if ( xhr.readyState == 4 ) {
switch (opts.data){
case "json":
opts.onSuccess(xhr.responseText);
break;
case "xml":
opts.onSuccess(xhr.responseXML);
break;
default :
opts.onSuccess(xhr.responseText);;
}
}
};
xhr.send(null);
}
var ajaxSample = function(e){
var callback = function( data ) {
document.getElementById("main").innerHTML += "<p>"
+data.getElementsByTagName("data")[0].getAttribute("value")
+"</p>";
}
ajax({
type: "GET",data: "xml"
})
e.preventDefault();
}
document.getElementById("activate").addEventListener("click",false);
清单 4 展示了现今更为常见的模式:采用 JSON 格式的 responseText,并将其解析成本机的 JavaScript 对象。这段代码演示了一个较为简单的 JSON 数据处理方法。为什么众多开发人员都选择使用 JSON 来传输数据,将该清单与操作 XML 数据所需的偶尔间接且冗长的方法进行比较,答案显而易见。 var ajax = function( opts ) {
opts = {
type: opts.type || "POST",data: opts.data || "xml"
};
var xhr = new XMLHttpRequest();
xhr.open(opts.type,true);
xhr.onreadystatechange = function(){
if ( xhr.readyState == 4 ) {
switch (opt.sdata){
case "json":
opt.onSuccess(xhr.responseText);
break;
case "xml":
opt.onSuccess(xhr.responseXML);
break;
default :
opt.onSuccess(xhr.responseText);;
}
}
};
xhr.send(null);
}
var jsonSample = function(e){
var callback = function( data ) {
//here,the data is actually a string
//we use JSON.parse to turn it into an object
data = JSON.parse(data);
/* we can then use regular JavaScript object references to get at our data. */
document.getElementById("main").innerHTML += "<p>"
+ data.sample.txt
+"</p>";
}
ajax({
type: "GET",url: "_assets/data/json-1.json",data : "json"
})
e.preventDefault();
}
document.getElementById("activate").addEventListener("click",jsonSample,false);
其余所有清单(清单 5 -11)都使用了 JSON 数据。 var callback = function( data ) {
document.getElementById("main").innerHTML += "<p>"+ data.sample.txt +"</p>";
}
var jsonpSample = function(e){
//create a script element
var jsonp = document.createElement("script");
//give it a source with the callback name appended in the query string
jsonp.src= "_assets/data/jsonp.php?callback=callback";
//add it to the doc
document.body.appendChild(jsonp);
e.preventDefault();
}
//wire up the event
document.getElementById("activate").addEventListener("click",jsonpSample,false);
库示例对于大多数开发人员来说,只有进行学术研究的人才会对 Ajax 请求的本质感兴趣。大多数实际工作是在一个或多个 JavaScript 库中完成。除了修补跨浏览器不兼容性,这些库都提供了构建于基础 API 之上的特性。下列示例展示了 3 个流行库中的 GET 和 POST 示例来介绍不同的 API。 jQuery让我们从流行 jQuery 库开始举例说明。jQuery 的 Ajax 函数最近进行了重写,将几个高级功能包含在内,这不是术语本文的讨论范围,但是所有 jQuery Ajax 请求的常见功能都以传递给该函数的配置对象的参数形式存在。另外还要注意的是,jQuery 有几个便利的方法,比如
/* callback is a simple function that will be run when the data is returned from the server */
var callback = function( data ) {
/* it just adds a little bit of text to the document data is the JSON object returned by the server. */
$("#main").append($("<p />").text(data.sample.txt));
}
/* Wire up the ajax call to this click event */
$("#activate").click(
function(){
//call $.ajax with a configuration object
$.ajax({
//it's just a get request
type: 'get',//we're looking for this URL
url: '_assets/data/json-1.json',//Our cool callback function
success: callback,//it's going to be JSON
dataType: "json"
})
}
)
清单 7 演示了如何发布和检索简单 JSON 对象。需要注意的是,这里使用了原生 JSON 对象来分析输入数据。jQuery 文档明确提及需要通过 JSON2.js 脚本增加不受支持的浏览器。 /* this is the object we're going to post */
var myMessages = {
positive : "Today is a good day",negative : "Today stinks",meh : "meh"
}
var callback = function( data ) {
$("#main").append($("<p />").text(data.positive));
}
/* Setting up a simple error handler. It doesn't do much. It's just nice to illustrate error handling. */
var errorHandler = function( xhr,textStatus,errorThrown ){
throw new Error("There was an error. The error status was " + textStatus );
}
/* Here's where the action happens. Attach an event to out simple button. */
$("#activate").click(
function(){
//call $.ajax with a configuration object
$.ajax({
//we're sending data to the server
type: 'POST',//this is our URL
url: '_assets/data/post-responder.php',/* This is our data,JSON stringified jQuery expects to use native JSON or JSON2.js in unsupported browsers */
data: JSON.stringify(myMessages),//Here's where we set up our callback function
success: callback,//The data expected from the server
dataType: "json",//And our simple error handler
error : errorHandler
}
)
}
);
DojoDojo 不仅仅是下列示例中演示的简单 Ajax 请求/DOM 操作。它实际上是为硬核应用程序开发而构建的。这就是说,以这种方式查看 API 仍然是值得期待的。 var callback = function( data ) {
//note the document.getelementById alias
dojo.byId("main").innerHTML += "<p>"+ data.sample.txt +"</p>";
}
var getData = function(){
//xhrGet is for get requests
dojo.xhrGet({
//the URL of the request
url: "_assets/data/json-1.json",//Handle the result as JSON data
handleAs: "json",//The success handler
load: callback
});
}
// Use connect to attach events
dojo.connect( dojo.byId("activate"),"onclick",getData );
清单 9 展示了一个 Dojo POST,包含一个错误句柄的配置。 var myMessages = {
positive : "Today is a good day",meh : "meh"
}
var callback = function( data ) {
dojo.byId("main").innerHTML += "<p>"+ data.positive +"</p>";
}
var errorHandler = function(){
throw new Error("We dun goofed.")
}
var postData = function(){
//not surprisingly xhrPost is for POST
dojo.xhrPost({
// The URL of the request
url: "_assets/data/post-responder.php",//This will be JSON
handleAs: "json",//Set the headers properly
headers: { "Content-Type": "application/json; charset=uft-8"},//Use Dojo's JSON utility
postData: dojo.toJson(myMessages),// The success handler
load: callback,// The error handler
error: errorHandler
});
}
// Use connect to attach events
dojo.connect( dojo.byId("activate"),postData );
Yahoo! 用户界面 (YUI)YUI 库提供一个与前面两个略有不同的模式。首先,YUI 返回整个 XHR 对象,不仅解析数据,还允许更准确地操作返回数据和整个请求的可见性。这也意味着开发人员需要了解 XHR 对象的来龙去脉。另外,这里还展示了 YUI 模块加载程序 use() 的使用,需要注意的是,即使与 Ajax 没有直接联系(除了加载 io 模块之外)。清单 10 中有一个 YUI 模块列表,还有一个用作参数的回调函数。一旦运行,就可以从 Yahoo! Content Delivery Network (CDN) 下载数据包,Yahoo! Content Delivery Network (CDN) 包含单个基于 CDN 的下载包中所需的所有模块。 // Create a new YUI instance and populate it with the required modules.
YUI().use('node','event','json','io',function (Y) {
var callback = function( id,xhr ) {
var data = Y.JSON.parse(xhr.responseText);
Y.one('#main').append("<p>"
+ data.sample.txt
+"</p>");
}
Y.one("#activate").on('click',function(){
Y.io( '_assets/data/json-1.json',{
//This is actually the default
method: 'get',on: {success: callback}
})
}
)
});
清单 11 中的 POST 示例中呈现的一个有趣的样式风格将所有响应函数进一步分割成 on 对象。 YUI().use('node',function (Y) {
var myMessages = {
positive : "Today is a good day",meh : "meh"
}
var callback = function( id,xhr ) {
var data = Y.JSON.parse(xhr.responseText);
Y.one('#main').append("<p>"
+ data.positive
+"</p>");
}
var errorHandler = function( id,xhr){
throw new Error("There was an error. The error status was "
+ xhr.statusText
+".")
}
Y.one("#activate").on('click',function(){
Y.io( '_assets/data/post-responder.php',{
method: 'post',//Use the Y.JSON utility to convert messages to a string
data : Y.JSON.stringify(myMessages),//All response methods are encapsulated in
//the on object
on: {success: callback,failure: errorHandler }
})
}
)
});
正如您所看到的,基本模式在多数清单中都是一样的。除了支持 ActiveX 控件和 JSONP 示例之外,它们基本上基于同一原理,只是在核心 JavaScript 交互的顶层具有不同的 API 变化。 下载资源本文的 Ajax 代码样例 (sample-ajax-code.zip | 18KB)(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |