3.9.4 jQuery对象的promise方法

jQuery 1.5开始,所有jQuery对象都增加了promise()方法,该方法返回一个Promise对象,通过该Promise 对象可以监听jQuery对象上动画队列的执行进度—通俗来说,就是可以为动画队列的执行失败、执行完成添加回调函数。

下面的例子来自jQuery的官方文档,该示例中定义了4个<div>元素以”渐隐”方式隐藏,程序还通过先调用promise()方法,再调用done()方法为它们添加回调函数。示例代码如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<!DOCTYPE html>
<html>

<head>
<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title> Deferred对象 </title>
<style type="text/css">
div {
height: 50px;
width: 50px;
float: left;
margin-right: 10px;
display: none;
background-color: #e0e;
}
</style>
</head>

<body>
<script type="text/javascript" src="../jquery-3.1.1.js"></script>
<button>开始</button>
<p>准备...</p>
<div></div>
<div></div>
<div></div>
<div></div>
<script type="text/javascript">
// 为button元素的click事件绑定事件处理函数
$("button").click(function () {
$("p").append(" 开始动画...");
// 迭代处理每个div元素
$("div").each(function (i) {
// 先让每个div元素以“渐显”方式显示出来
// 在让每个div元素以“渐隐”方式隐藏起来,隐藏所需要时间不同
$(this).fadeIn().fadeOut(1000 * (i + 1));
});
// 为所有div元素上动画队列执行完成时指定回调函数
// ①号代码
$("div").promise().done(function () {
$("p").append(" 动画完成! ");
});
});
</script>
</body>

</html>

该程序中①号代码用于为所有<div>元素的动画队列执行完成后添加回调函数。在浏览器中执行该页面,将可以看到当动画完成后,页面会再追加上”动画完成!”字符串。

3.9.3 为普通对象增加Defered接口

如果调用Deferred对象的promise()方法时传入了一个对象作为参数,Deferred对象将会为该参数对象增加Deferred接口,这样即可在该参数对象上调用Deferred对象的方法来添加回调函数。

以下为示例程序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<!DOCTYPE html>
<html>

<head>
<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title> Deferred对象 </title>
</head>

<body>
<script type="text/javascript" src="../jquery-3.1.1.js">
</script>
<script type="text/javascript">
// 已有的对象
var object =
{
hello: function (name) {
document.write(name + ",您好!<br/>");
}
};
// 创建一个Deferred对象
var defer = $.Deferred();
// 为object对象增加Deferred接口
defer.promise(object); // ①
// 将object当成Promise对象使用
// 可以多次调用done来注册多个回调函数,持久操作完成时,这些回调函数会依次执行.
object.done(function (name) {
object.hello(name);
}).done(function (name) {
document.write("执行完成了:" + name + "<br/>");
});
// 将Deferred对象的状态设为resolved,
// 这将激发object对象上通过done()方法添加的回调函数
defer.resolve("孙悟空"); // ②
</script>
</body>

</html>

该程序中①号粗体字代码调用promise(object)方法为object对象添加了Deferred接口,接下来为该对象调用done()方法绑定了两个回调函数,
程序在②号粗体字代码处将该Deferred对象的状态改为resolved,这将会激发object对象上通过done()方法添加的两个回调函数。

3.9.2 为多个耗时操作指定回调函数

jQuery提供了一个jQuery.when(deferreds)工具方法,该方法可用于将多个Deferred对象组合成一个Deferred对象,从而允许开发者为多个Deferred对象同时指定耗时操作。
例如如下代码片段:

1
2
3
$when($.ajax({url: "pro"}),calPrime(1, 10000)) //①
.done(function(){})
.fail(function(){});

程序中的①号代码调用$.when()方法将ajaxcalPrime这两个耗时操作组合成一个Defered对象,从而允许开发者为它们整体指定回调函数:

  • $.ajax({url:"pro"})calPrime(1,10000)都执行成功时,将会自动激发done()方法添加的回调函数;
  • 只要任意一个执行失败,都将激发fail()方法添加的回调函数。

3.9 jQuery的Deferred对象

在进行JavaScript开发的过程中,经常会遇到要执行耗时任务的情况,该任务可能是远程Ajax 调用,也可能是本地的耗时操作,总之不能立即有结果。遇到这种情况,通常就需要采用回调函数来监听该耗时操作的执行情况,当耗时操作执行完成后,自动激发相应的回调函数。jQuery为解决这类问题提供了Deferred对象。

3.9.1 jQuery的异步调用

jQuery以前的版本中,当我们使用$.ajax()方法进行Ajax调用时,通常的代码格式如下:

1
2
3
4
5
6
$.ajax({
url:"pro",
data:$("#userForm").serializeArray(),
success:successFunction,
error:errorFunction
});

在该Ajax调用中通过successerror分别指定了调用成功、调用失败时的回调函数,这是jQuery传统的管理回调函数的方式,这种方式虽然简单、直观,但编程一致性并不好,因为调用不同耗时操作时可能需要通过不同选项来指定回调函数。
Deferred 对象则改变了这种局面,Deferred 对象允许用”一致”的代码来管理回调函数。例如通过done()方法添加回调成功的回调函数,通过fail()方法添加调用失败的回调函数……从jQuery 1.5开始,$.ajax()方法返回的就是Deferred对象,因此jQuery允许我们采用如下形式来完成Ajax调用。

下面的示例使用Deferred对象改写了前面的Ajax示例,程序如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<!DOCTYPE html>
<html>

<head>
<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>使用jQuery的get方法</title>
</head>

<body>
<h3>请输入你的信息:</h3>
<form id="userForm">
用户名: <input type="text" name="user" /> <br /> 喜欢的图书: <select
multiple="multiple" name="books">
<option value="java">疯狂Java讲义</option>
<option value="javaee">轻量级Java EE企业应用实战</option>
<option value="ajax">疯狂前端开发讲义</option>
<option value="xml">疯狂XML讲义</option>
</select> <br /> <input id="load" type="button" value="发送异步GET请求" />
</form>
<hr>
<div id="show"></div>
<script src="jquery-3.1.1.js" type="text/javascript">

</script>
<script type="text/javascript">
// 为id为load的按钮绑定事件处理函数
$("#load").click(function() {
// `$.ajax()`方法返回的就是`Deferred`对象
$.ajax({
url : "pro",
data : $("#userForm").serializeArray()
})
// 使用`Deferred`对象的done()方法添加“执行成功”的回调函数
.done(function(data, statusText) {
$("#show").empty();
$("#show").append("服务器响应状态为:" + statusText + "<br />");
$("#show").append(data);
})
// 使用`Deferred`对象的fail方法添加“执行失败”的回调函数
.fail(function() {
alert("服务器响应出错!");
});
});
</script>
</body>
</html>

该程序调用了$.ajax()方法来发送异步请求,该方法将会返回一个Deferred 对象,接下来通过Deferred对象的done()方法和fail()方法分别添加调用成功、调用失败的回调函数。
提示:通过上面的示例不难看出jQueryDeferred的设计:

Deferred其实就是JavaScript新增的Promise对象。它们都可对所有”耗时操作”的回调函数进行统一管理,就像jQuery最初提供的jQuery对象一样。**jQuery对象对所有DOM元素进行了统一管理,从而提供了一致的编程模型。而Deferred对象或Promise对象则可对所有耗时操作进行统一管理**。因此jQuery完全可能对原有的Ajax进行全新设计,从传统编程模型全面过渡到使用Deferred来管理回调函数。

Deferred详解

如何创建Deferred对象

除了可以调用$.ajax()方法返回Deferred对象之外,jQuery专门提供了**jQuery.Deferred()方法来创建Deferred对象**。

Deferred提供的3个耗时状态

Deferred对象提供了以下三种状态来表示耗时操作的执行结果:

  1. pending状态:pending表示任务执行中,未完成。此时将执行Deferred对象progress()方法添加的回调函数。
  2. fulfilled状态:fulfilled表示任务完成了,该任务会执行resolve函数;进而执行Deferred对象done()方法添加的回调函数。
  3. rejected状态:rejected表示任务失败了,该任务会执行reject函数;进而执行fail()方法添加的回调函数。

修改Deferred状态的方法

为了让开发者手动改变Deferred对象的状态,Deferred还提供了reject(args)resolve(args)两个方法,其中

  • reject(args)方法用于将Deferred对象改为”任务失败“状态,
  • resolve(args)方法用于将Deferred对象改为”任务完成“状态。

Deferred对象的方法详解

Deferred对象支持的方法如下。

监听操作的方法

方法 描述
progress(progressCallbacks) 指定在Deferred对象包含的异步操作执行过程中激发的回调函数。
done(doneCallbacks) 指定Deferred对象包含的异步操作执行成功后激发的回调函数。
fail(doneCallbacks) 指定Deferred对象包含的异步操作执行失败后激发的回调函数。
always(alwaysCallbacks [,alwaysCallbacks]) 该方法相当于done()fail()两个方法的合体。也就是说,无论Deferred对象包含的异步操作执行成功还是执行失败,总会激发该方法指定的回调函数。
then(doneCallbacks,failCallbacks [,progressCallbacks]) then()方法相当于done()fail()、和progress()三个方法的综合版本,该方法可以分别为Deferred对象包含的异步操作在完成时失败时进行中指定一个或多个回调函数。

调用监听操作方法的方法

方法 描述
notify(args) 调用在Deferred对象上通过progress()方法添加的函数,args作为参数传入progress()方法添加的函数。
notifyWith(context [,args]) 类似于notify(args)方法的功能,只是激发progress()方法添加的函数时将传入contextargs参数。
reject(args) Deferred对象状态改为”rejected(任务已失败)”,在Deferred 对象上通过fail()方法添加的函数将会被激发,args作为参数传入fail()方法添加的函数。
rejectWith(context [,args]) 类似于reject(args)方法的功能,只是激发fail()方法添加的函数时将传入contextargs参数。
resolve(args) Deferred对象状态改为”rejected(任务已完成)”,在Deferred对象上通过done()方法添加的函数将会被激发,args作为参数传入done()方法添加的函数。
resolveWith(context [,args]) 类似于resolve(args)方法的功能,只是激发done()方法添加的函数时将传入contextargs参数。

返回Promise对象的方法

方法 描述
promise([target]) 返回Deferred对象对应的Promise对象(它相当于Deferred对象的副本,不允许开发者通过Promise对象修改Deferred对象的状态)。如果指定了target参数,则会在该参数指定的对象上增加Deferred接口。

查询一步操作所处的执行状态

方法 描述
state() 返回Deferred对象包含的异步操作所处的执行状态。
该方法返回表示执行状态的字符串,可能返回如下三个字符串。
  1. pending:任务执行中,未完成。
  2. resolved:任务完成。
  3. rejected:任务失败。

程序示例

下面的程序定义了一个耗时操作。程序需要统计出指定范围的所有质数,由于这个过程耗时较长,因此考虑使用Deferred对象来管理回调函数。JavaScript代码如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<!DOCTYPE html>
<html>

<head>
<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title> Deferred对象 </title>
</head>

<body>
<script type="text/javascript" src="../jquery-3.1.1.js">
</script>
<script type="text/javascript">
var calPrime = function (start, end) {
// 定义一个Deferred对象
var dfd = $.Deferred(); // ①
try {
var result = "";
search:
for (var n = start; n <= end; n++) {

for (var i = 2; i <= Math.sqrt(n); i++) {
// 如果除以n的余数为0,开始判断下一个数字。
if (n % i == 0) {
continue search;
}
}
// 搜集找到的质数
result += (n + ",");
}
// 当整个“耗时任务”执行完成时,将Deferred对象的状态改为resolved
dfd.resolve(result); // ②
}
catch (e) {
// 如果程序出现异常,将Deferred对象的状态改为rejected
dfd.reject("任务失败"); // ③
}
return dfd.promise();
}
// 调用calPrime()耗时函数
calPrime(1, 1000000)
// 通过done()方法添加回调函数
.done(function (result) {
$("body").append(result);
})
// 通过fail()方法添加回调函数
.fail(function (result) {
$("body").append("计算出错了!");
});
</script>
</body>

</html>

该程序中①号代码创建了一个Deferred 对象,该对象用于标识该耗时任务的完成进度:

  • 当任务完成时,程序调用Deferred对象的resolve()方法将它的状态设为resolved;
  • 当任务出错时,程序调用Deferred对象的reject()方法将它的状态设为rejected

calPrime()方法返回Deferred对象的Promise对象,

Promise对象相当于Deferred对象的副本,但程序不能通过Promise对象来改变Deferred对象的状态—通过这种方式,即可避免别人在方法外改变Deferred对象的状态。

Deferred对象用于表示calPrime()耗时操作的完成状态,因此通常只应该在该方法内改变Deferred对象的状态。为了保证效果,建议将Deferred对象定义成该方法的局部变量,并让该方法返回Deferred对象的Promise对象。
在浏览器中执行该JavaScript代码,即可看到当calPrime()耗时操作执行完成后,会自动回调done()方法指定的回调函数。

3.8.4 使用get或post方法

发送get请求

jQuery提供了以下几种简便方法来发送GET请求。

get方法

方法 描述
jQuery.get(url,[data],[callback],[type]) url发送异步的GET请求。
该方法参数说明如下:
  1. url参数表示要请求的URL
  2. data参数是一个JavaScript对象,用于指定请求参数;
  3. callback参数指定服务器响应成功时的回调函数,该函数是一个形如function(data,statusText,jqXHR){...}的函数。该函数的data参数是服务器响应,statusText参数是服务器响应类型的描述信息,jqXHR参数表示发送异步请求的XMLHttpRequest对象,
  4. type参数指定服务器响应数据的类型,支持xmljsonscripttexthtml这几种类型。

getJSON方法

方法 描述
jQuery.getJSON(url [,data] [,callback]) 该函数是前一个函数的JSON版本,相当于指定type参数为”json"

getScript方法

方法 描述
jQuery.getScript(url [,data] [,callback]) 该函数是第一个函数的Script版本,相当于指定type参数为”script"

程序示例

下面通过一个简单的Java Web项目来做示范,项目结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
E:\workspacne_jQuery\get
├─src\
│ └─org\
│ └─crazyit\
│ └─jquery\
│ └─web\
│ └─ProServlet.java
└─WebContent\
├─get.html
├─getScript.html
├─img\
│ └─indicator.gif
├─jquery-3.1.1.js
├─META-INF\
│ └─MANIFEST.MF
├─script.jsp
└─WEB-INF\
├─lib\
└─web.xml

使用get方法

get.html页面示范了如何使用jQuery.get()方法来发送异步GET请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<!DOCTYPE html>
<html>

<head>
<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title> 使用jQuery的get方法 </title>
</head>

<body>
<h3>请输入你的信息:</h3>
<form id="userForm">
用户名:<input type="text" name="user" /><br />
喜欢的图书:<select multiple="multiple" name="books">
<option value="java">疯狂Java讲义</option>
<option value="javaee">轻量级Java EE企业应用实战</option>
<option value="ajax">疯狂前端开发讲义</option>
<option value="xml">疯狂XML讲义</option>
</select><br />
<input id="load" type="button" value="发送异步GET请求" />
</form>
<hr />
<div id="show"></div>
<script src="jquery-3.1.1.js" type="text/javascript">
</script>
<script type="text/javascript">
// 为id为load的按钮绑定事件处理函数
$("#load").click(function () {
// 指定向pro发送请求,以id为userForm表单里各表单控件的值作为请求参数
$.get(
// 请求的URL
"pro",
// 请求的参数
$("#userForm").serializeArray(),
// 收到响应时要调用的回调函数
// 第1个参数data表示服务器的响应,
// 第2个参数表示服务器的响应状态
function (data, statusText) {
$("#show").empty();
$("#show").append("服务器响应状态为:" + statusText + "<br>");
$("#show").append("服务器响应内容为:" + data);
},
// 要求服务器的响应类型为HTML
"html"
);
});
</script>
</body>

</html>

该页面代码使用了jQuery.get()方法向pro这个URL发送异步GET请求,处理pro这个URLProServlet.java的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package org.crazyit.jquery.web;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.*;

@WebServlet(urlPatterns = "/pro")
public class ProServlet extends HttpServlet
{
private static final long serialVersionUID = 953022779069495267L;

public void service(HttpServletRequest request,
HttpServletResponse response) throws IOException, ServletException
{
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
// 获取请求参数
String user = request.getParameter("user");
String[] books = request.getParameterValues("books");

// 生成HTML字符串 响应
out.println(user + ",您好,现在时间是:" + new java.util.Date());
out.println(",您喜欢的图书如下:");
out.println("<ol>");
for (int i = 0; i < books.length; i++)
{
out.println("<li>" + books[i] + "</li>");
}
out.println("</ol>");
}
}

使用getScript方法

getScript.html页面中使用jQuery.getScript()方法发送请求,让服务器直接生成JavaScript脚本作为响应,从而通过服务器的JavaScript脚本响应直接操作当前页面。getScript.html代码如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>使用jQuery的getScript方法</title>
</head>
<body>
<ul style="display: none">
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
<input id="get" type="button" value="getScript" />
<div id="show"></div>
<script src="jquery-3.1.1.js" type="text/javascript"></script>
<script type="text/javascript">
// 为id为get的按钮绑定事件处理函数
$("#get").click(function() {
$.getScript("script.jsp");
});
</script>
</body>
</html>

程序中使用jQuery.getScript()方法向script.jsp发送发送异步GET请求,虽然没有指定请求参数,也没有指定回调函数,但是这没有关系,script.jsp页面将直接生成JavaScript脚本作为响应,这些JavaScript脚本将直接修改当前HTML页面。下面是script.jsp页面的代码。

1
2
3
4
5
6
7
8
9
10
11
12
<%@ page contentType="text/javascript; charset=utf-8" language="java" %>
$("ul>li").each(function(index)
{
if(index % 2 == 0)
{
$(this).css("background-color" , "#ccffcc");
}
$(this).empty();
$(this).append("服务器响应" + index);
});
// 缓慢增加高度显示
$("ul").slideDown(1000);

JSP页面不再输出HTML标签,它包含的全部是JavaScript代码,这些**JavaScript代码将作为响应传给客户端浏览器,并由客户端浏览器来解释执行**。

发送POST请求

jQuery也提供了一个发送POST 请求的方法,该方法与前面的jQuery.get()方法并无太大的区别,甚至连参数、选项都完全相同,只是该方法发送的是异步的POST请求。关于该方法的详细说明如下。

方法 描述
jQuery.post(url,[data],[callback],[type]) url发送异步的POST请求。

该方法中的各参数与jQuery.get()方法中各参数的功能和意义完全相同。因为jQuery.get()jQuery.post()两个方法的用法、功能基本一样,它们的区别只是发送GET请求和POST请求的区别,故此处不再给出jQuery.post()的程序示例。

什么使用用get方法什么时候用post方法

如果用户需要发送请求的请求参数量不是太大,通常使用jQuery.get()方法即可;
如果需要发送的请求参数量较大,则建议使用jQuery.post()方法发送请求

3.8.3 jQuery.ajax(options)方法与jQuery.ajaxSetup(options)方法

jQuery.ajax(options)既可以发送GET请求,也可以发送POST请求,甚至可以发送同步请求。使用该方法,开发者可以获得Ajax交互的全部控制权。
jQuery.ajax(options)jQuery Ajax支持的底层实现,该方法返回创建的XMLHttpRequest对象。
大部分时候开发者无须理会它返回的XMLHttpRequest对象,但在特殊情况下其可用于手动终止请求。

ajax函数的参数

ajax函数只需要一个options参数,此参数是一个形如{key1:value1,key2,value2...}JavaScript对象,用于指定发送Ajax请求的各种选项,各选项的说明如下。

ajax函数选项

async选项

async:指定是否使用异步请求,该选项默认是true

contentType选项

contentType:指定发送请求到服务器时所使用的内容编码类型。该选项的默认值是”application/x-www-form-urlencoded",该默认值适合大多数应用场合。

beforeSend选项

beforeSend:指定发送请求之前将触发的函数。通过指定该函数,可以在发送请求之前添加自定义的请求头。该选项指定的函数是一个形如function(xhr){...}的函数,其中xhr就是本次Ajax请求所使用的XMLHttpRequest对象。如果让该函数返回false,即可取消本次Ajax请求。

data选项

data:发送本次Ajax请求的请求参数。该选项既可使用JavaScript对象,也可以使用查询字符串。如果指定为JavaScript 对象,系统会自动将其转换为查询字符串(除非将processData设为false)。当指定该选项值为形如{key1:value1,key2:value2...}的对象,且其中valuen为数组时,系统自动将它们转换为多个请求参数,例如{foo:["bar1","bar2"]}将会被转换为'&foo=bar1&foo=bar2'

type选项

type:设置发送请求的方式,最常用的两个值是"POST""GET",该选项默认值是"GET"

url选项

url:指定发送Ajax请求的目的URL地址。

timeout选项

timeout:设置Ajax请求超时时长。

processData选项

processData:指定是否需要处理请求数据。如果传给data选项的不是字符串,而是一个JavaScript对象,则jQuery自动将其转换成查询字符串。如果不希望jQuery进行这种转换,则可将该选项指定为false

安全授权相关选项

password选项

password:指定密码。如果目标URL是需要安全授权的地址,则通过该选项指定密码。

username选项

username:指定用户名。如果目标URL是需要安全授权的地址,则通过该选项指定用户名。

响应相关选项

complete选项

complete:指定Ajax交互完成后的回调函数,该回调函数将在successerror回调函数之后被执行。该选项指定的函数是一个形如function(xhr,textStatus){...}的函数,其中xhr是本次Ajax交互所使用的XMLHttpRequest 对象,而textStatus则是服务器响应状态的描述信息。

success选项

success:指定Ajax响应成功后的回调函数。该选项指定的函数是一个形如function(xhr,textStatus){...}的函数,
其中,xhr是本次执行Ajax交互所使用的XMLHttpRequest 对象,而textStatus 则是服务器响应状态的描述信息。

error选项

error:指定服务器**响应出现错误时的回调函数**。该选项指定的函数是一个形如function(xhr,textStatus,errorThrown){...}的函数。
其中:

  • xhr是本次发送Ajax 请求的XMLHttpRequest对象,
  • textStatus是关于错误的描述信息,
  • errorThrown是引起错误的错误对象。

dataFilter选项

dataFilter:该选项执行一个回调函数,该回调函数将会对服务器响应进行预处理。该选项指定的函数是一个形如function(data,type){…}的函数,其中data表示从服务器返回的响应,而type表示服务器响应的数据类型(也就是下面dataType选项中指定的值)。服务器响应数据经过该选项指定的回调函数处理之后将会更加有序。

dataType选项

dataType:指定服务器响应的数据类型。如果不指定,jQuery将自动根据响应的MIME信息返回responseXMLresponseText,并将响应传给回调函数对应的参数。该选项支持如下值:

  • xml,返回可使用jQuery处理的XML文档。
  • html,返回HTML文本。该HTML文本里可以使用<script.../>标签包含JavaScript脚本。
  • script,返回JavaScript脚本,此时将禁止从浏览器缓存里加载信息。jQuery将会自动执行服务器响应的JavaScript脚本。
  • json,返回一个符合JSON格式的字符串,jQuery会将该响应转换成JavaScript对象。
  • jsonp,指定使用JSONP加载JSON块。当使用JSONP格式时,该在请求URL之后额外添加”?callback=?",其中callback将作为回函数。
  • text:返回普通文本响应。

ifModified选项

ifModified:设置是否仅在服务器数据改变时获取新数据。系统将根据HTTPLast-Modified响应头进行判断。该选项默认是false

jsonp选项

jsonp:该选项指定的值将会覆盖JSONP请求中的callback函数。也就是说,该选项指定的值将会覆盖查询字符串里的′callback=?′部分,即{jsonp:'onJsonPLoad'}将导致'onJsonPLoad=?'被传给服务器。

scriptCharset选项

scriptCharset:该选项仅对dataType是′jsonp′或′script′的情况有效。该选项设置系统使用给定的字符集来解释请求,仅当服务器响应和本地页面使用不同字符集时需要指定该选项。

其他选项

cache选项

cache:如果该选项被指定为false,将不会从浏览器缓存里加载信息。该选项默认值为true;如果服务器响应是”script",则该选项默认是false

global选项

global:设置是否触发Ajax的全局事件处理函数,该选项默认是true

xhr选项

xhr:该选项指定一个函数,该函数用于创建XMLHttpRequest对象。只有开发者想用自己的方式来创建XMLHttpRequest对象时才需要使用该选项。

如何设置全局Ajax选项

通过指定上面这些选项,开发者可以全面控制Ajax请求的各种细节。但在大部分情况下,开发者都不会使用jQuery.ajax(options)来发送Ajax请求,而是使用另两个更简便的方法getXxxpost。当开发者使用这两个方法来发送请求时,jQuery将使用全局Ajax选项。为了设置全局Ajax选项,jQuery提供了如下方法。

方法 描述
jQuery.ajaxSetup(options) jQueryAjax交互设置全局选项,其中options参数和jQuery.ajax(options)里的options参数的功能和意义完全一样。

3.8.2 使用load方法

load方法是一个使用起来非常便捷的Ajax交互方法,它向远程url发送一个异步请求,甚至无须指定回调函数。load方法的说明如下。

方法 描述
load(url[,data][,callback]) 向远程url 发送异步请求,并直接将服务器响应插入当前jQuery对象匹配的DOM 元素之内。其中data 是一个形如{key1:value1,key2:value2...}JavaScript对象,表示发送请求的请求参数;callback用来指定Ajax交互成功后的回调函数。

程序示例

下面的程序示范了如何使用load方法进行Ajax交互。

项目结构

这是一个简单Java Web项目,项目结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
E:\workspace_web2\load
├─src
│ └─org
│ └─crazyit
│ └─jquery
│ └─web
│ └─ProServlet.java
└─WebContent
├─img
│ └─indicator.gif
├─index.html
├─jquery-3.1.1.js
└─WEB-INF
├─lib
└─web.xml

web.xml

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<display-name>load</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>

index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!DOCTYPE html>
<html>

<head>
<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title> 使用jQuery的load方法 </title>
</head>

<body>
<h3>请输入你的信息:</h3>
<form id="userForm">
用户名:
<input type="text" name="user" />
<br /> 喜欢的图书:
<select multiple="multiple" name="books">
<option value="java">疯狂Java讲义</option>
<option value="javaee">轻量级Java EE企业应用实战</option>
<option value="ajax">疯狂前端开发讲义</option>
<option value="xml">疯狂XML讲义</option>
</select>
<br />
<input id="load" type="button" value="Load" />
</form>

<hr />
<div id="show"></div>

<script src="jquery-3.1.1.js" type="text/javascript"></script>

<script type="text/javascript">
// 为id为load的按钮绑定事件处理函数
$("#load").click(function () {
// 把响应插入到id为show的元素内
$("#show").load("pro", $("#userForm").serializeArray());
});
</script>
</body>

</html>

在该程序中使用了jQueryserializeArray()方法来获取请求参数,使用了load()方法来发送Ajax请求,没有指定回调函数,
$("#show").load()方法会把服务器的HTML响应将会填充到idshowdiv元素内.

服务器响应代码

该应用中处理服务器响应的ProServlet的代码如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package org.crazyit.jquery.web;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.*;

@WebServlet(urlPatterns = "/pro")
public class ProServlet extends HttpServlet
{
private static final long serialVersionUID = 953022779069495267L;

public void service(HttpServletRequest request,
HttpServletResponse response) throws IOException, ServletException
{
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
// 获取请求参数
String user = request.getParameter("user");
String[] books = request.getParameterValues("books");
// 生成HTML字符串 响应
out.println(user + ",您好,现在时间是:" + new java.util.Date());
out.println("<br />您喜欢的图书如下:");
out.println("<ol>");
for (int i = 0; i < books.length; i++)
{
out.println("<li>" + books[i] + "</li>");
}
out.println("</ol>");
}
}

这是一个非常简单的Servlet,该Servlet负责生成一个HTML字符串响应。当用户浏览前面的index.html页面,并单击"load"按钮时,将可看到index.html页面会自动加载/pro这个URL的响应,而响应则显示在idshow<div>元素内。

从上面的程序可以看出,使用load方法发送Ajax请求简单便捷,开发者同样无须理会创建XMLHttpRequest对象的细节。如果开发者需要管理发送Ajax请求的细节,则可考虑使用jQuery.ajax(options)方法,该方法有点类似于Prototype库的Ajax.Request方法,使用jQuery.ajax方法可获得Ajax交互的全部控制权。

3.8 Ajax相关方法

jQuery的另一个吸引人的功能就是它所提供的Ajax 支持。jQuery 提供了大量关于Ajax的工具方法,这些工具方法可以帮助开发者完成Ajax开发的大量通用操作,开发者只需指定发送Ajax请求的URL、回调函数即可,甚至连回调函数都可以省略

3.8.1 三个工具方法

jQueryAjax提供了三个工具方法,这三个工具方法的功能很强大,它们不仅可用于处理表单,也可用于处理一个或多个表单控件。下面是关于这三个方法的简要说明

jQuery名字空间下的param方法

方法 描述
jQuery.param(object) object参数(对象或数组)转换成查询字符串

jQuery对象的方法

方法 描述
serialize() jQuery对象包含的表单或表单控件转换成查询字符串
serializeArray() jQuery对象包含的表单或表单控件转换为一个对象数组,每个数组元素都是形如{name:fieldName,value:fieldValue}的对象,其中fieldName 是对应表单控件的name属性,fieldValue是对应表单控件的value属性。

程序示例

下面的页面程序示范了这两个工具方法的用法。
程序清单:codes\03\3.8\serialize.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<!DOCTYPE html>
<html>

<head>
<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title> 处理表单 </title>
</head>

<body>
<form id="test">
用户名:<input id="user" name="user" type="text" /><br />
个人介绍:<textarea id="desc" name="desc"></textarea><br />
喜欢的图书:
<select id="book" name="book">
<option value="java">疯狂Java讲义</option>
<option value="javaee">轻量级Java EE企业应用实战</option>
<option value="ajax">疯狂前端开发讲义</option>
</select>
</form>
<button id="bn1">查询字符串</button>
<button id="bn2">查询JSON对象</button>
<button id="bn3">将对象转换为查询字符串</button>
<hr />
<span id="show"></span>

<script type="text/javascript" src="../jquery-3.1.1.js">
</script>
<script type="text/javascript">
// 为id为bn1的按钮绑定事件处理函数
$("#bn1").click(function () {
// 将id为test1的表单转换为查询字符串
$("#show").html($("#test").serialize());
});
// 为id为bn2的按钮绑定事件处理函数
$("#bn2").click(function () {
// 将所有输入元素转换为 对象数组
var arr = $(":input").serializeArray();
// 清空
$("#show").empty();
// 遍历 对象数组
for (var index in arr) {
$("#show").append("第" + index + "表单控件名为:" +
arr[index].name + ",值为:" + arr[index].value + "<br />");
}
});
$("#bn3").click(function () {
// 调用$.param将对象转换为查询字符串
$("#show").html('{name:"疯狂Java讲义", price:109}' +
'转换出的查询字符串为:<br/>' +
$.param({
name: "疯狂Java讲义",
price: 109
}));
});
</script>
</body>

</html>

这个页面程序中的两个按钮分别使用了serialize方法和serializeArray方法来处理表单,第三个按钮则使用param方法将JavaScript对象转换成查询字符串
在浏览器中浏览该页面,为页面上两个文本框输入内容,为1个下拉列表框选择值,然后
单击页面上第一个按钮。第一个按钮调用**serialize方法将表单内所有表单控件的名值对转换为查询字符串**。此时可以看到如下输出:

1
user=xiaoming&desc=%E6%88%91%E6%98%AF%E5%B0%8F%E6%98%8E&book=java

单击页面上的第二个按钮。第二个按钮调用serializeArray方法将该表单内所有表单控件名值对转换为JavaScript对象数组。此时可以看到如下输出:

1
2
3
第0表单控件名为:user,值为:xiaoming
第1表单控件名为:desc,值为:我是小明
第2表单控件名为:book,值为:java

单击页面上的第三个按钮。第三个按钮调用param方法将JavaScript对象转换为查询字符串。此时可以看到如下输出:

1
2
{name:"疯狂Java讲义", price:109}转换出的查询字符串为:
name=%E7%96%AF%E7%8B%82Java%E8%AE%B2%E4%B9%89&price=109

总结

  • jQuery.param方法可以把JavaScript对象转换成查询字符串
  • jQuery对象.serialize方法可以把所有表单控件的值转换成查询字符串
  • jQuery对象.serializeArray方法可以把所有表单控件的值转换为JavaScript对象数组

3.7.2 创建Callbacks对象支持的选项

使用jQuery.Callbacks()创建Callbacks对象时,可以传入可选的flags参数,该参数是一个以空格分隔的字符串列表,表示如何改变回调函数列表的行为,例如$.Callbacks('unique stopOnFalse')
jQuery支持下列选项。

选项 描述
once 保证整个Callbacks对象只能被fire()一次。
memory 缓存前一次调用的参数。当执行完fire()Callback会缓存这次fire方法传入的参数,对于新添加的任何回调函数,会自动触发该回调函数,并传入缓存的参数作为新添加的回调函数的参数。
unique 保证一个回调函数最多只被添加一次,也就是说,Callbacks 对象中不会出现重复的回调函数。
stopOnFalse 当某回调函数返回false时,立即中断调用

程序示例

下面的程序代码示范了创建Callbacks时各选项的功能。

one选项的用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!DOCTYPE html>
<html>

<head>
<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title> 回调支持 </title>
</head>

<body>
<script type="text/javascript" src="../jquery-3.1.1.js"></script>
<script type="text/javascript">
// 定义两个简单的函数
function fn1(value) {
document.writeln("fn1函数输出:" + value + "<br />");
}
function fn2(value) {
document.writeln("fn2函数输出:" + value + "<br />");
return false;
}
// 使用"once"选项创建一个回调函数列表:整个`Callbacks`对象只能被`fire()`一次
var callbacks = $.Callbacks("once");
// 向回调函数列表中添加第一个回调函数
callbacks.add(fn1);
// 触发回调函数列表中的所有回调函数(只有fn1被触发)
callbacks.fire("疯狂前端开发");
// 再次向回调函数列表中添加一个回调函数
callbacks.add(fn2);
document.writeln("<hr/>");
// 触发回调函数列表中的所有回调函数,此时不会起任何作用。
callbacks.fire("~~疯狂Java~~");
</script>
</body>

</html>

在创建Callbacks对象时指定了”once"选项,这表明该Callbacks对象只能被触发一次。

memory选项的用法

以下代码示范了memory选项的用法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<!DOCTYPE html>
<html>

<head>
<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title> 回调支持 </title>
</head>

<body>
<script type="text/javascript" src="../jquery-3.1.1.js">
</script>
<script type="text/javascript">
// 定义两个简单的函数
function fn1(value) {
document.writeln("fn1函数输出:" + value + "<br />");
}
function fn2(value) {
document.writeln("fn2函数输出:" + value + "<br />");
return false;
}
// 使用特定选项创建一个回调函数列表
var callbacks = $.Callbacks("memory");
// 向回调函数列表中添加第一个回调函数
callbacks.add(fn1);
// 触发回调函数列表中的所有回调函数(只有fn1被触发)
// "疯狂前端开发"参数将会被缓存
callbacks.fire("疯狂前端开发");
// 添加并触发fn2函数,以前一次调用fire的参数作为自动触发的参数.
callbacks.add(fn2);
document.writeln("<hr/>");
// 再次触发回调函数列表中的所有回调函数(fn1、fn2被触发)
// "疯狂Java"参数将会被缓存
callbacks.fire("疯狂Java");
// 从回调函数列表中删除fn1、fn2函数
callbacks.remove([fn1, fn2]);
document.writeln("<hr/>");
// 添加并触发fn1函数,以前一次调用fire的参数作为自动触发的fn1的参数.
callbacks.add(fn1);
</script>
</body>

</html>

在创建Callbacks 时指定了”memory"选项,这表明Callbacks 对象将会保留上次调用fire()方法的参数,并以该参数自动激发新添加的回调函数

stopOnFalse选项

以下代码示范了stopOnFalse选项的用法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<!DOCTYPE html>
<html>

<head>
<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title> 回调支持 </title>
</head>

<body>
<script type="text/javascript" src="../jquery-3.1.1.js">
</script>
<script type="text/javascript">
// 定义两个简单的函数
function fn1(value) {
document.writeln("fn1函数输出:" + value + "<br />");
return false;
}
function fn2(value) {
document.writeln("fn2函数输出:" + value + "<br />");
return false;
}
// 使用stopOnFalse选项创建一个回调函数列表:当某回调函数返回`false`时,立即中断调用
var callbacks = $.Callbacks("stopOnFalse");
// 向回调函数列表中添加第一个回调函数
callbacks.add(fn1);
// 触发回调函数列表中的所有回调函数(只有fn1被触发)
callbacks.fire("疯狂前端开发");
// 再次向回调函数列表中添加一个回调函数。
callbacks.add(fn2);
document.writeln("<hr/>");
// 再次触发回调函数列表中的所有回调函数,
// 依然只有fn1被触发,因此fn1返回了false,它阻止了fn2被触发)
callbacks.fire("疯狂Java");
</script>
</body>

</html>

在创建Callbacks时指定了”stopOnFalse"选项,这表明该Callbacks对象触发回调函数列表时,只要任一个回调函数返回了false,都将会导致后面的回调函数不会被调用。

使用多个选项

不仅如此,创建Callbacks对象时,还可传入多个空格隔开的选项,多个选项的效果将会被”累加”。例如$.Callbacks("unique memory")创建的Callbacks对象既会缓存前一次调用fire()方法的参数,也会保证Callbacks对象中不出现重复的回调函数。

3.7 jQuery的回调支持

jQuery 1.7开始,jQuery提供了回调支持,这使得开发者能以一种更简单、高效的方式管理回调函数。

3.7.1 回调支持的基本用法

如何创建Callbacks对象

jQuery提供了以下方法创建Callbacks对象。

方法 描述
jQuery.Callbacks(flags) 根据创建的flags创建并返回Callbacks对象,Callbacks对象表示一个回调函数列表

得到回调函数列表之后,接下来就可以利用该回调函数列表来管理回调函数了。

程序示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<!DOCTYPE html>
<html>

<head>
<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title> 回调支持 </title>
</head>

<body>
<script type="text/javascript" src="../jquery-3.1.1.js">
</script>
<script type="text/javascript">
// 定义两个简单的函数
function fn1(value) {
document.writeln("fn1函数输出:" + value + "<br />");
}
function fn2(value) {
document.writeln("fn2函数输出:" + value + "<br />");
return false;
}
// 创建一个回调函数列表
var callbacks = $.Callbacks();
// 向回调函数列表中添加第一个回调函数
callbacks.add(fn1);
// 触发回调函数列表中的所有回调函数(只有fn1被触发)
callbacks.fire("疯狂前端开发");
// 再次向回调函数列表中添加一个回调函数
callbacks.add(fn2);
document.writeln("<hr/>");
// 触发回调函数列表中的所有回调函数(fn1、fn2被触发)
callbacks.fire("~~疯狂Java~~");
// 从回调函数列表中删除fn1函数
callbacks.remove(fn1);
document.writeln("<hr/>");
// 触发回调函数列表中的所有回调函数(只有fn2被触发)
callbacks.fire("fkjava.org");
</script>
</body>

</html>

该程序中使用$.Callbacks()方法创建一个Callbacks 对象(回调函数列表),接下来

  • 程序既可使用add()方法向该Callbacks对象添加回调函数;
  • 也可使用remove()方法从Callbacks对象中删除回调函数;
  • 还可使用fire()方法触发Callbacks对象中的所有回调函数。

Callbacks对象方法

从上面的程序可以看出,Callbacks 对象是一种简单有效的回调函数管理方式。Callbacks对象提供了以下几种方法来管理回调函数。

添加或删除回调函数到Callbacks对象中

方法 描述
add(callbacks) 将一个或多个回调函数添加到Callbacks对象中。callbacks参数表示将要添加的回调函数或回调函数数组。
remove(callbacks) Callbacks 对象中删除一个或多个回调函数。callbacks 参数表示将要被删除的回调函数或回调函数数组。
empty() 清空Callbacks对象中的所有回调函数。

执行Callbacks对象中的所有回调方法

方法 描述
fire(arguments) 使用指定参数arguments激发Callbacks对象中所有回调函数。

判断方法

方法 描述
has(callback) 判断Callbacks对象中是否包含callback回调函数。
fired() 判断Callbacks对象中的回调函数是否被调用了至少一次。
locked() 判断Callbacks对象是否处于锁定状态。

禁用或锁定Callbacks对象

方法 描述
disable() 禁用Callbacks对象。
lock() Callbacks对象锁定在当前状态。