触碰jQuery:AJAX异步详解

触碰jQuery:AJAX异步详解

传送门:异步编程系列目录……javascript

示例源码:触碰jQuery:AJAX异步详解.rarphp

AJAX 全称 Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。它并不是一种新的技术,而是如下几种原有技术的结合体。html

1)   使用CSS和XHTML来表示。html5

2)   使用DOM模型来交互和动态显示。java

3)   使用XMLHttpRequest来和服务器进行异步通讯。jquery

4)   使用javascript来绑定和调用。web

经过AJAX异步技术,能够在客户端脚本与web服务器交互数据的过程当中使用XMLHttpRequest对象来完成HTTP请求(Request)/应答(Response)模型:ajax

1)   不须要用户等待服务端响应。在异步派发XMLHttpRequest请求后控制权立刻就被返回到浏览器。界面不会出现白板,在获得服务器响应以前还能够友好的给出一个加载提示。正则表达式

2)   不须要从新加载整个页面。为XMLHttpRequest注册一个回调函数,待服务器响应到达时,触发回调函数,而且传递所需的少许数据。“按需取数据”也下降了服务器的压力。编程

3)   不须要使用隐藏或内嵌的框架。在XHR对象以前,模拟Ajax通讯一般使用hack手段,如使用隐藏的或内嵌的框架(<iframe>标签)。

下面介绍下AJAX中的重要对象:XMLHttpRequest。

 

XMLHttpRequest对象(XHR)

XMLHttpRequest是一套能够在Javascript、VbScript、Jscript等脚本语言中经过http协议传送或接收XML及其余数据的一套API。

XMLHttpRequest对象首次以ActiveX对象形式在微软Internet Explorer(IE) 5中以引入。其余浏览器制造商在认识到这一对象重要性后也纷纷实现了XMLHttpRequest对象,可是以一个本地JavaScript对象而不是做为一个ActiveX对象实现。而现在,因为安全性、标准等问题,微软已经在其IE 7中把XMLHttpRequest实现为一个本地JavaScript对象。

 

API

描述

 

客服端请求

open(method,url,async, bstrUser, bstrPassword)

规定请求的类型、URL 以及是否异步处理请求。

1)   method:请求的类型,例如:POST、GET、PUT及PROPFIND。大小写不敏感。

2)   url:请求的URL地址,能够为绝对地址也能够为相对地址。

3)   async[可选]:true(默认,异步)或 false(同步)。

注释:当您使用async=false 时,JavaScript 会等到服务器响应就绪才继续执行。若是服务器繁忙或缓慢,应用程序会挂起或中止。此时,不须要编写onreadystatechange回调函数,把代码放到 send()语句后面便可。

4)   bstrUser[可选]:若是服务器须要验证,此处指定用户名,若是未指定,当服务器须要验证时,会弹出验证窗口。

5)   bstrPassword[可选]:验证信息中的密码部分,若是用户名为空,则此值将被忽略。

getRequestHeader(name)

获取指定的相应头部信息

setRequestHeader(name,value)

自定义HTTP头部信息。需在open()方法以后和send()以前调用,才能成功发送请求头部信息。

传送门:HTTP 头部详解

Accept

浏览器可以处理的媒体类型

Accept-Charset

浏览器申明本身接收的字符集

Accept-Encoding

浏览器申明本身接收的编码方法,一般指定压缩方法,是否支持压缩,支持什么压缩方法(gzip,deflate)

Host

客户端指定要请求的WEB服务器的域名/IP 地址和端口号

Referer

发出请求的页面的URI

Content-Type

标明发送或者接收的实体的MIME类型。传送门:

1HTTP Content-type对照表

2格式:Content-Type: [type]/[subtype]; parameter

X-Requested-With

非标准HTTP头,只为firefox3标注是否为ajax异步请求,null表示为同步请求。

默认状况下,服务器对POST请求和提交Web表单不会一视同仁,将Content-Type头部信息设置为application/x-www-form-urlencoded (模拟表单提交)

send(string)

将请求发送到服务器。参数string仅用于POST请求;对于GET请求的参数写在url后面,因此string参数传递null。

abort()

调用此方法可取消异步请求,调用后,XHR对象中止触发事件,不容许访问任何与响应相关的属性;

 

服务端响应

onreadystatechange事件

对于异步请求,若是须要对服务器获取和操做响应结果,则在send() 以前,须要为onreadystatechange属性指定处理方法。该函数用于对服务器响应进行处理。

readyState

存有XMLHttpRequest的状态。每当readyState改变时,就会触发onreadystatechange事件。

从 0 到 4 发生变化:

0(未初始化)

对象已创建,可是还没有初始化(还没有调用open方法)

1(初始化)

对象已创建,还没有调用send方法

2(发送数据)

send方法已调用,可是当前的状态及http头未知

3(数据传送中)

已接收部分数据,由于响应及http头不全,这时经过responseBody和responseText获取部分数据会出现错误

4(完成)

数据接收完毕,此时能够经过responseXml和responseText获取完整的回应数据

 

status(数字表示)

返回当前请求的http状态码。

传送门:HTTP状态码一览表(HTTP Status Code

1xx(临时响应)

表示临时响应并须要请求者继续执行操做的状态代码。

2xx (成功)

表示成功处理了请求的状态代码。Eg:200

3xx (重定向)

表示要完成请求,须要进一步操做。一般,这些状态代码用来重定向。Eg:304

4xx(请求错误)

这些状态代码表示请求可能出错,致使服务器没法正常处理。Eg:404

5xx(服务器错误)

这些状态代码表示服务器在尝试处理请求时发生内部错误。这些错误多是服务器自己的错误,而不是请求出错。Eg:500

 

statusText(字符表示)

返回当前请求的状态文本eg:OK  (status:200)

responseText

将响应信息做为字符串返回

responseXML

将响应信息格式化为Xml Document对象并返回

responseBody(只有微软的IE支持)

将响应信息正文以unsigned byte数组形式返回(二进制数据)

responseStream(只有IE的某些版本支持)

以Ado Stream对象(二进制流)的形式返回响应信息

getResponseHeader(name)

从响应信息中获取指定的http头

getAllResponseHeaders()

获取响应的全部http头

overrideMimeType

一般用于重写服务器响应的MIME类型。Eg,正常状况下XMLHttpRequest只接收文本数据,但咱们能够重写MIME为“text/plain; charset=x-user-defined”,以欺骗浏览器避免浏览器格式化服务器返回的数据,以实现接收二进制数据。

 

一个简单的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
var  myAjax = {
     // XMLHttpRequest IE7+, Firefox, Chrome, Opera, Safari ;  ActiveXObject IE6, IE5
     xhr: window.XMLHttpRequest ? new  XMLHttpRequest() : new  ActiveXObject( 'Microsoft.XMLHTTP' ),
     get: function  (url, callback) {
         this .xhr.open( 'get' , url);
         this .onreadystatechange(callback, this .xhr);
         this .xhr.send( null );       
     },
     post: function  (url, data, callback) {
         this .xhr.open( 'post' , url);
         this .xhr.setRequestHeader( 'Content-Type' , 'application/x-www-form-urlencoded' );
         this .onreadystatechange(callback, this .xhr);
         this .xhr.send(data);
     },
     onreadystatechange: function  (func, _xhr) {
         _xhr.onreadystatechange = function  () {
             if  (_xhr.readyState == 4) {
                 if  (_xhr.status == 200) {
                     func(_xhr.responseText);
                 }
             }
         }
     }
}

使用:

1
2
3
4
5
6
7
8
9
$( '#btn_nowTime1' ).bind( 'click' , null
     , function  () {
         myAjax.post( 'AjaxHandler.ashx' , 'func=GetServerTime'
             , function  (data) {
                 if  (data)
                     alert(data);
             }
         );
     });

 

XMLHttpRequest Level 2

XMLHttpRequest是一个浏览器接口,使得Javascript能够进行 HTTP (S) 通讯。可是,这个接口一直没有标准化,每家浏览器的实现或多或少有点不一样。HTML 5 的概念造成后,W3C 开始考虑标准化这个接口。2008年 2 月,提出了XMLHttpRequest Level 2 草案。

  1. 老版本的缺点

老版本的XMLHttpRequest对象有如下几个缺点:

1)   只支持文本数据的传送,没法用来读取和上传二进制文件。

2)   传送和接收数据时,没有进度信息,只能提示有没有完成。

3)   受到"同域限制"(Same Origin Policy),只能向同一域名的服务器请求数据。

  1. 新版本的功能

新版本的XMLHttpRequest对象,针对老版本的缺点,作出了大幅改进。

1)   能够设置 HTTP 请求的时限。

2)   可使用FormData对象管理表单数据。

3)   能够上传文件。

4)   能够请求不一样域名下的数据(跨域资源共享,Cross-origin resource sharing,简称 CORS)。

5)   能够获取服务器端的二进制数据。

6)   能够得到数据传输的进度信息。

  1. 介绍几个XMLHttpRequest Leve2 新增的成员

 

超时时限

timeout

设置ajax请求超时时限,过了这个时限,就自动中止 HTTP请求。

ontimeout事件

当ajax超过timeout 时限时触发的回调函数。

 

指定响应格式

responseType

(默认:“text”)在发送请求前,根据您的数据须要,将xhr.responseType设置为“text”、“arraybuffer”、“blob”或“document”。

response

成功发送请求后,xhr的响应属性会包含DOMString、ArrayBuffer、Blob 或 Document 形式(具体取决于responseTyp的设置)的请求数据。

 

进度信息

progress 事件

在XMLHttpRequest对象传递数据的时候用来返回进度信息。它分红上传和下载两种状况。下载的 progress 事件属于XMLHttpRequest对象,上传的 progress 事件属于XMLHttpRequest.upload对象。即:

xhr.onprogress = updateProgress;

xhr.upload.onprogress = updateProgress;

XHR还新增了与progress事件相关的五个事件:

1)   load 事件:传输成功完成。

2)   abort 事件:传输被用户取消。

3)   error 事件:传输中出现错误。

4)   loadstart事件:传输开始。

5)   loadEnd事件:传输结束,可是不知道成功仍是失败。

  1. 一个新功能实例

1)   接收二进制数据(方法A:改写MIMEType)

老版本的XMLHttpRequest对象,只能从服务器取回文本数据。但咱们能够改写数据的MIMEType,将服务器返回的二进制数据假装成文本数据,而且告诉浏览器这是用户自定义的字符集

关键代码以下:

服务端

1
2
3
4
5
6
7
8
9
10
11
     String str = "二进制数据获取" ;
     MemoryStream _memory = new  MemoryStream();
     BinaryFormatter formatter = new  BinaryFormatter();
     formatter.Serialize(_memory, str);
     _memory.Position = 0;
     byte [] read = new  byte [_memory.Length];
     _memory.Read(read, 0, read.Length);
     _memory.Close();
     context.Response.ContentType = "text/plain" ;
// 服务器使用OutputStream输出二进制流
     context.Response.OutputStream.Write(read, 0, read.Length);

客服端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$( '#btn_mime' ).bind( 'click' , null
     , function  () {
         $.ajax( 'AjaxHandler.ashx?func=GetBinaryData' ,
             {
                 type: 'get' ,
                 dataType: 'text' ,
                 cache: false ,
                 mimeType: 'text/plain; charset=x-user-defined' ,
                 success: function  (data) {
                     if  (data) {
                         var  byte = [];
                         for  ( var  i = 0, len = data.length; i < len; ++i) {
                             var  c = data.charCodeAt(i);
                             byte[byte.length] = c & 0xff;
                         }
                         alert(byte);
                     }
                 }
             });
     });

浏览器会把相应数据当作文本数据接收,因此咱们还必须再一个个字节地还原成二进制数据。位运算"c & 0xff",表示在每一个字符的两个字节之中,只保留后一个字节,将前一个字节扔掉。缘由是浏览器解读字符的时候,会把字符自动解读成Unicode 的 0xF700-0xF7ff 区段。

截图以下:(测试环境:google Chrome 版本 26.0.1410.43)

服务器端返回二进制数据:

 

客服端输出:

a)   使用mimeType: 'text/plain; charset=x-user-defined'参数。

     

b)   没有对服务器的MIME类型进行重写,致使返回信息被浏览器格式化后输出的二进制数据与服务器不一样而且不一样浏览器格式化后输出的二进制数据都有差别。

     

 

2)   接收二进制数据(方法B:responseType属性)

在XMLHttpRequest Level2中,可使用新增的responseType属性从服务器取回二进制数据。把responseType设为 blob,表示服务器传回的是二进制对象。

1
2
3
var  xhr = new  XMLHttpRequest();
xhr.open ( 'GET' '/path/to/image.png' );
xhr.responseType = 'blob' ;

接收数据的时候,用浏览器自带的 Blob 对象便可。注意,读取的xhr.response,而不是xhr.responseText。

1
var  blob = new  Blob ([xhr.response], {type: 'image/png' });

还能够将responseType设为arraybuffer,把二进制数据装在一个数组里。而后再遍历这个数组。

1
2
3
4
5
6
7
8
9
10
var  xhr = new  XMLHttpRequest ();
xhr.open ( 'GET' '/path/to/image.png' );
xhr.responseType = "arraybuffer" ;
var  arrayBuffer = xhr.response;
if  (arrayBuffer) {
var  byteArray = new  Uint8Array (arrayBuffer);
     for  (vari = 0; i<byteArray.byteLength; i++) {
         // do something
     }
}
  1. 更多XMLHttpRequest Level 2新功能描述请看:

1)   XMLHttpRequest 加强功能

2)   XMLHttpRequest Level 2 使用指南

3)   XMLHttpRequest2 新技巧

 

jQuery框架的Ajax

    jQuery是一个快速、简单的JavaScript library,核心理念是write less,do more(写的更少,作的更多)。它简化了HTML 文件的traversing,事件处理、动画、Ajax 互动,从而方便了网页制做的快速发展。jQuery是为改变你编写JavaScript 的方式而设计的。更多jQuery科普知识请看:jQuery百度百科(Eg:模块,历史版本)

    下面介绍下jQuery框架中ajax相关API:

    版本Jquery-1.7.1.js。

 

  1. jQuery.ajax( [url,] options )

    经过 HTTP 请求加载远程数据。

返回值:$.ajax() 返回jqXHR对象(jqXHR对象:为XMLHttpRequest对象的超集)。可用于手动终止请求abort()、为ajax函数设置额外的回调函数等。

 

ajax内部实现的两个重要对象:s对象和jqXHR对象。

1)   s对象

由默认设置jQuery.ajaxSettings对象、options参数集合和jQuery.ajaxSetup({})默认设置合并而成s对象。

参数名

描述

 

可由ajax的options参数设置

url

(默认: 当前页地址) 要请求的目的URL地址。

username

password

用于响应HTTP访问认证请求的用户名及密码

type

(默认: "GET") 请求方式 ("POST" 或 "GET")。注意:其它 HTTP 请求方法,如 PUT 和 DELETE 也可使用,但仅部分浏览器支持。

dataType

预期服务器返回的数据类型。若是不指定,jQuery将自动根据 HTTP 包 MIME 信息来智能判断,好比 XML MIME 类型就被识别为 XML。随后服务器端返回的数据会根据这个值解析后,传递给回调函数。

必须确保网页服务器报告的 MIME 类型与咱们选择的dataType所匹配。好比说,XML的话,服务器端就必须声明 text/xml 或者 application/xml 来得到一致的结果。

可用值:

"xml"

返回 XML 文档,可用jQuery处理。

"html"

返回纯文本 HTML 信息;包含的 script标签会在插入dom时执行

"script"

返回纯文本 JavaScript 代码,经常用于跨域请求。不会触发全局事件和局部事件;只支持GET方式(POST请求会自动转化为GET请求);默认不启用缓存(cache:false)

"json"

返回 JSON 数据。JSON 数据是一种能很方便经过 JavaScript 解析的结构化数据。

"jsonp"

JSONP 格式,用于跨域请求。

"text"

返回纯文本字符串

其中,text 和 xml 类型返回的数据不会通过处理。数据仅仅简单的将XMLHttpRequest的responseText或responseHTML属性传递给 success 回调函数。

若是指定了 script 或者jsonp类型,那么当从服务器接收到数据时,其实是用了<script>标签而不是XMLHttpRequest对象。这种状况下,$.ajax() 再也不返回一个XMLHttpRequest对象,而且也不会传递事件处理函数,好比beforeSend。

contentType

(默认: "application/x-www-form-urlencoded")标明发送或者接收的实体的MIME类型。当“非GET或HEAD请求”的HTTP请求时,会被设置为HTTP头请求信息。

mimeType

多用途互联网邮件扩展(MIME,Multipurpose Internet Mail Extensions);用于重写服务器端响应的MIME类型。

data

发送到服务器的数据。能够是一个查询字符串,好比 key1=value1&amp;key2=value2 ,也能够是一个映射,好比 {key1: 'value1', key2: 'value2'} 。若是使用了后者的形式,则数据在发送前会经过jQuery.param()函数转换成查询字符串。这个处理过程也能够经过设置processData选项为false来回避。

processData

(默认: true) 默认状况下,发送到服务器的数据(即data参数)将被转换为字符串以配合默认内容类型"application/x-www-form-urlencoded"。若是要发送 DOM 树信息或其它不但愿转换的信息,请设置为false。

jQuery中的处理方式:

1
2
3
if  ( s.data&&s.processData&&typeofs.data !== "string"  ) {
     s.data = jQuery.param(s.data, s.traditional );
}

async

(默认: true) 默认设置下,全部请求均为异步请求。若是须要发送同步请求,请将此选项设置为 false。注意,同步请求将锁住浏览器,用户其它操做必须等待请求完成才能够执行。

timeout

设置请求超时时间(毫秒)。经过setTimeout(fn,time)实现。

cache

(默认: true)dataType为 script 和jsonp时默认为 false。设置为 false 将不缓存此页面。

当使用GET或HEAD方式发送请求时要添加时间戳参数 (net Date()).getTime() 来保证每次发送的URL不一样, 能够避免浏览器缓存.(只有GET和HEAD方式的请求浏览器才会缓存)

jQuery中的处理方式:

1
2
3
4
5
6
7
if  ( s.cache === false  ) {
     var  ts = jQuery.now(),
     // rts = /([?&])_=[^&]*/尝试替换
     ret = s.url.replace( rts, "$1_="  + ts );
     // rquery = /\?/若是没有替换任何内容,则把时间戳加到url最后
     s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&"  : "?"  ) + "_="  + ts : ""  );
}

示例:/AjaxHandler.ashx?func=GetBinaryData&_=1368424995535

ifModified

(默认: false) 仅在服务器数据改变时获取新数据。经过响应头If-Modified-Since、IF-None-Match和请求头Last-Modified、Etag提升GET或HEAD方式请求效率。(只有GET和HEAD方式的请求浏览器才会缓存)

global

(默认: true) 是否触发全局 AJAX 事件。设置为 false 将不会触发全局AJAX 事件:ajaxStart、ajaxSend、ajaxSuccess、ajaxError、ajaxComplete、ajaxStop。(好比请求频繁时可禁用全局AJAX事件提升效率)

context

(默认:true)  这个对象用于设置Ajax相关回调函数的上下文,让回调函数内this指向这个对象。若是不设定这个参数,那么回调函数中的this就指向调用本次AJAX请求时传递的options参数载体“s对象”。但对于全局Ajax事件来讲,this都是指向全局事件所绑定的元素。

jsonp

指定得到jsonp回调函数名的参数名(默认为:callback)。这个值用来替代URL中"callback=?"里的"callback"部分,好比{jsonp:'onJsonPLoad'}会替换为将"onJsonPLoad=?"传给服务器。

jsonpCallback

为jsonp请求指定一个回调函数名。jsonpCallback参数通常为字符串,也可接收函数(该函数返回字符串)。

默认状况下生成随机函数名:"jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ) + jQuery.now()

crossDomain

(默认:null)false:同域请求;true跨域请求。

假若crossDomain标识为null,则jQuery会自动根据本地url、端口来解析。能够根据需求直接赋值来提升性能。

一般状况下由服务器自动解析便可,但若是你想在同一域中强制跨域请求(像JSONP同样),那么将crossDomain为true,这容许你将服务器端重定向到另外一个域。

scriptCharset

只有当请求时dataType为"jsonp"或"script",而且type是"GET"才会用于修改charset。

由于此时是动态建立<script>来完成脚本加载,可是若是js中的编码与页面的编码不一致时,js可能加载失败或者显示乱码或者IE下报某符号错误。设置此参数就至关于为<script>标签设置charset属性。

hearders

(默认:{})  设置HTTP请求头数据"{键:值}"。此设置发生在:jQuery全部影响HTTP头的参数(options)设置以后,beforeSend回调函数以前

statusCode

(默认:{})  定义一组HTTP状态码与回调函数的映射,当响应的状态码有匹配statusCode则会触发对应回调函数。例如,若是响应状态是404,将触发如下警报:

1
2
3
4
5
$.ajax({
     statusCode: {404: function () {
        alert( 'page not found' );
     }
});

traditional

若是你想要用传统的方式来序列化数据,那么就设置为true。请参考$.param()深度递归详解

xhrFields

声明附加到XMLHttpRequest对象的自定义“key-value”数组。例如,若是须要的话,你能够用它来设置跨域的withCredentials为true,即:

xhrFields: { withCredentials: true }  

5个局部事件

beforeSend、dataFilter、success、error、complete。(详见后面事件介绍部分)

 

由ajax函数内部解析或内部提供

dataTypes

由dataType按空格拆分所得。

isLocal

根据协议肯定当前url请求的是否为本地请求。

jQuery中定义默认值为:

1
isLocal:/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/.test(/^([\w\+\.\-]+:)(?:\/\/([^\/? #:]*)(?::(\d+))?)?/.exec(url))

hasContent

非GET或HEAD请求为true,用于处理data和contentType参数。

contents

一个"{类型字符串:正则表达式}"的对象,假若dataTypes[0]为“*”时,用contents中的正则表达式去匹配contentType,匹配成功则用“类型字符串”覆盖dataTypes[0]。

jQuery内部定义以下:

1
2
3
4
5
6
contents: {
     xml: /xml/,
     html: /html/,
     json: /json/,
     script: /javascript|ecmascript/
}

accepts

浏览器可以处理的媒体类型,其值取决于dataTypes[0]参数。

jQuery内部定义以下:

1
2
3
4
5
6
7
8
accepts: {
     xml: "application/xml, text/xml" ,
     html: "text/html" ,
     text: "text/plain" ,
     json: "application/json, text/javascript" ,
     script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript" ,
     "*" : allTypes    // dataTypes[0]匹配不上时取此值
}

responseFields

jqXHR超集设置“数据类型:属性”对应关系,在返回响应数据时,用于肯定建立哪一个属性变量。

jQuery中定义以下:

1
2
3
4
responseFields: {
     xml: "responseXML" ,
     text: "responseText"
}

converters

存储数据类型对应的转换器,根据dataTypes获取对应转换器,用于对响应数据response进行处理。该处理发生在dataFilter回调函数以后。

1
2
3
4
5
6
7
8
9
10
converters: {
     "* text" : window.String,
     "text html" : true ,
     "text json" : jQuery.parseJSON,
     "text xml" : jQuery.parseXML,
     "text script" : function ( text ) {
             jQuery.globalEval( text );  // 执行脚本
             return  text;
         }
}
     

2)   jqXHR对象

为不一样浏览器内置的XMLHttpRequest提供了一致的超集。对于XMLHttpRequest以外的传输机制,好比JSONP请求,jXHR对象也能够进行处理。

超集与真子集:

若是一个集合S2中的每个元素都在集合S1中,且集合S1中可能包含S2中没有的元素,则集合S1就是S2的一个超集。 S1是S2的超集,则S2是S1的真子集,反之亦然。

    jqXHR对象咱们经常使用以下成员,这些成员主要用于ajax的全局事件和局部事件,而且作为$.ajax()函数返回值返回。

1
2
3
4
5
6
7
8
9
10
jqXHR:{
     readyState
     ,setRequestHeader: function ( name, value )
     ,getAllResponseHeaders: function ()
     ,getResponseHeader: function ( key )
     ,overrideMimeType: function ( type )
     ,abort: function ( statusText )
     ,responseText
     ,responseXML
}

另外,jqXHR的所有成员以下:

 

    在图中咱们看到一些陌生的函数,好比:done()、fail()、promise()、isResolve()、isRejected()、then()、always()、progress()等,都是jQuery的deferred对象API。

开发网站的过程当中,咱们常常遇到某些耗时很长的javascript操做。其中,既有异步的操做(好比ajax读取服务器数据),也有同步的操做(好比遍历一个大型数组),它们都不是当即能获得结果的。

    一般的作法是,为它们指定回调函数(callback)。即事先规定,一旦它们运行结束,应该调用哪些函数。可是,在回调函数方面,jQuery的功能很是弱。为了改变这一点,jQuery开发团队就设计了deferred对象。

简单说,deferred对象就是jQuery的回调函数解决方案。在英语中,defer的意思是"延迟",因此deferred对象的含义就是"延迟"到将来某个点再执行。 它解决了如何处理耗时操做的问题,对那些操做提供了更好的控制,以及统一的编程接口。

更专业的资源:jQuery的deferred对象详解

 

  1. jQuery Ajax事件

jQuery框架中,伴随Ajax请求会触发若干事件,咱们能够订阅这些事件并在其中处理咱们的逻辑。在jQuery中有两种Ajax事件:局部事件和全局事件。

1)   局部事件(回调函数),在$.ajax()方法的options参数中声明,能够用来设置请求数据和获取、处理响应数据。

beforeSend

该函数可在发送请求前修改XMLHttpRequest对象,如添加自定义 HTTP 头。

签名:function (jqXHR,s) { }

函数说明:传入jqXHR、s对象

dataFilter

在请求成功以后调用。若状态码为304(未修改)则不触发此回调。

签名:function (data, dataType) { return newData; }

函数说明:传入返回的数据、"dataType"参数的值。而且必须返回新的数据传递给success回调函数

success

请求成功时触发。

签名:function (data,statusText,jqXHR) { }

函数说明:传入返回的数据、描述状态的字符串”success”、jqXHR对象

error

请求失败时调用此函数。

签名:function (jqXHR, textStatus, errorThrown) { }

函数说明:传入jqXHR对象、描述状态的字符串”error”、错误信息

complete

请求完成后回调函数 (请求成功或失败以后均调用)

签名:function (jqXHR, textStatus) { }

函数说明:传入jqXHR对象、描述状态的字符串(可能值:"No Transport"、"timeout"、"notmodified"---304 "、"parsererror"、"success"、"error")

        定义方式例如:

1
2
3
4
5
6
7
8
9
10
$.ajax({
     // ...
     beforeSend: function (){
         // Handle the beforeSend event
     },
     complete: function (){
         // Handle the complete event
     }
     // ...
});

2)   全局事件,每次Ajax请求都会触发,它会向DOM中的全部元素广播,你只需为DOM中任意元素bind好全局事件即会触发(若绑定屡次,则会依次触发为事件注册的回调函数)

ajaxStart

开始新的Ajax请求,而且此时jQuery对象上没有其余ajax请求正在进行。

签名:function(e)

函数说明:传入事件对象

ajaxSend

当一个Ajax请求开始时触发

签名:function(e,jqXHR,s)

函数说明:传入事件对象、jqXHR、s对象

ajaxSuccess

全局的请求成功

签名:function(e,jqXHR,s,data)

函数说明:传入事件对象、jqXHR、s对象、请求成功返回的相应数据

ajaxError

全局的发生错误时触发

签名:function(e,jqXHR,s,errorData)

函数说明:传入事件对象、jqXHR、s对象、请求失败返回的错误信息

ajaxComplete

全局的请求完成时触发

签名:function(e,jqXHR,s)

函数说明:传入事件对象、jqXHR、s对象

ajaxStop

当jQuery对象上正在进行Ajax请求都结束时触发。

签名:function(e)

函数说明:传入事件对象

全局事件在jQuery中的声明方式:

1
2
3
4
5
jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend" .split( " "  ), function ( i, o ){
         jQuery.fn[ o ] = function ( f ){
         return  this .on( o, f );
     };
});

    因此咱们可使用下面两种方式定义全局事件:

1
2
3
4
// 能够用bind来绑定,用unbind来取消绑定。
$( "#loading" ).bind( "ajaxSend" , function (){ … });
或者:
$( "#loading" ).ajaxStart( function (){ … });

3)   ajax方法完整的事件流

    

    

4)   示例:$.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
48
49
50
51
// 全局事件
$( "#div_event" ).ajaxStart( function  (e) {
     doAddEvent4textarea( 'txt_event' , '触发ajaxStart回调函数' );
});
$( "#div_event" ).ajaxSend( function  (e) {
     doAddEvent4textarea( 'txt_event' , '触发ajaxSend回调函数' );
});
$( "#div_event" ).ajaxSuccess( function  (e, jqXHR, s, data) {
     doAddEvent4textarea( 'txt_event' , '触发ajaxSuccess回调函数' );
});
$( "#div_event" ).ajaxError( function  (e, jqXHR, s, errorData) {
     doAddEvent4textarea( 'txt_event' , '触发ajaxError回调函数' );
});
$( "#div_event" ).ajaxComplete( function  (e, jqXHR, s) {
     doAddEvent4textarea( 'txt_event' , '触发ajaxComplete回调函数' );
});
$( "#div_event" ).ajaxStop( function  (e) {
     doAddEvent4textarea( 'txt_event' , '触发ajaxStop回调函数' );
});
// 局部事件
function  bindLocalEvent(e) {
     var  textareaid = e.data.textareaid;
     var  global = e.data.global;
 
     $.ajax( 'AjaxHandler.ashx?func=btn_nowTime_long' ,
         {
             type: 'get' ,
             dataType: 'text' ,
             global: global,
             cache: false ,
             beforeSend: function  (jqXHR, s) {
                 doAddEvent4textarea(textareaid, '触发beforeSend回调函数' );
             },
             dataFilter: function  (data, dataType) {
                 doAddEvent4textarea(textareaid, '触发dataFilter回调函数' );
             },
             success: function  (data, statusText, jqXHR) {
                 doAddEvent4textarea(textareaid, '触发success回调函数' );
             },
             error: function  (jqXHR, textStatus, errorThrown) {
                 doAddEvent4textarea(textareaid, '触发error回调函数' );
             },
             complete: function  (jqXHR, textStatus) {
                 doAddEvent4textarea(textareaid, '触发complete回调函数' );
             }
         });
}
function  doAddEvent4textarea(textareaid, txt) {
     var  textarea = $( "#"  + textareaid);
     textarea.val(textarea.val() + '\r\n'  + txt);
}

        效果图:

           

5)   $.ajax()方法的全局事件典型用例

你的页面存在多个甚至为数很多的ajax请求,可是这些ajax请求都有相同的消息机制。ajax请求开始前显示一个提示框,提示“正在读取数据”;ajax请求成功时提示框显示“数据获取成功”;ajax请求结束后隐藏提示框。

a)   不使用全局事件的作法是:

给$.ajax()加上beforeSend、success、complete回调函数,在回调函数中加上处理提示框。

b)   使用全局事件的作法是:

1
2
3
4
5
6
$(document).ajaxStart(onStart)
                    .ajaxComplete(onComplete)
                    .ajaxSuccess(onSuccess);
function  onStart(event) { //..... }
function  onComplete(event, xhr, settings) { //..... }
function  onSuccess(event, xhr, settings) { //..... }
  1. jQuery ajax相关函数

1)   jQuery.ajaxSetup({ })

jQuery.ajax()函数中的全部的参数选项均可以经过jQuery.ajaxSetup()函数来全局设置默认值。

2)   $.ajax()函数的封装

a)   $("").load(url [, params] [, callback])

请求远程的HTML文件代码(dataType: "html"),默认使用 GET 方式,若是传递了params参数则使用Post方式。在请求“成功”完成时将responseText属性值插入至DOM中。但无论请求是否成功完成“在最后”都会执行callback回调函数(即:complete:callback)。

b)   jQuery.get(url [, data] [, callback] [, type] )

经过HTTP GET请求载入数据,并在请求成功时执行回调函数(即:success: callback)。

c)   jQuery.getJSON(url [, data] [, callback] )

经过 HTTP GET 请求载入 JSON 数据。至关于: jQuery.get(url, [data],[callback], "json")

能够经过使用JSONP 形式的回调函数来加载其余网域的JSON数据。

d)   jQuery.getScript(url [, callback] )

经过 HTTP GET 请求载入并执行一个 JavaScript 文件。至关于: jQuery.get(url, null, [callback], "script")

能够跨域调用 JavaScript 文件。

e)   jQuery.post(url [, data] [, callback] [, type] )

经过 HTTP POST 请求载入信息,并在请求成功时执行回调函数(即:success: callback)。

3)   对象序列化

a)   jQuery.param(object,traditional)

建立数组或对象的序列化表示,该序列化可在ajax请求时在URL查询字符串中使用。

序列化过程当中会使用encodeURIComponent()函数把字符串做为URI组件进行编码。

encodeURIComponent() 方法不会对 ASCII 字母和数字进行编码,也不会对这些 ASCII 标点符号进行编码: - _ . ! ~ * ' ( ) 。其余字符(好比:;/?:@&=+$,# 这些用于分隔 URI 组件的标点符号),都是由一个或多个十六进制的转义序列替换的。

1
2
3
4
5
6
// 在param中会进行以下处理
function ( key, value ) {
     // 若是value是函数,则取其函数返回值
     value = jQuery.isFunction( value ) ? value() : value;
     s[ s.length ] = encodeURIComponent( key ) + "="  + encodeURIComponent( value );
};

对于 jQuery 1.4,$.param() 方法将会经过深度递归的方式序列化对象,以便符合现代化脚本语言的需求,好比PHP、Ruby on Rails 等。你能够传递traditional = true 或在ajax功能中传递包含traditional的options参数。

           传送门:$.param()深度递归详解$.param() 示例

b)   $("").serializeArray()

能够将一个或多个表单元素(好比 input、 textarea等),或者 form 元素自己的jQuery对象序列化为JSON对象。(非 JSON 字符串。须要使用插件或者第三方库进行字符串化操做)

特别说明,元素不能被禁用(禁用的元素不会被包括在内),而且元素应当有含有 name 属性。提交按钮的值也不会被序列化。文件选择元素的数据也不会被序列化。

           传送门:$("").serializeArray() 示例

c)   $("").serialize()

能够将一个或多个表单元素(好比 input、 textarea等),或者 form 元素自己的jQuery对象序列化为通过URL编码转换后的字符串,可直接用在URL查询字符串中。

       jQuery内部定义:

1
2
3
serialize: function () {
     return  jQuery.param( this .serializeArray() );
}

传送门:$("").serialize()示例

 

$.ajax()中常见应用示例

  1. cache和ifModified参数

1)   cache参数:GET和POST最重要的区别(传送门)

语义上,GET是获取指定URL上的资源,是读操做,重要的一点是不论对某个资源GET多少次,它的状态是不会改变的,在这个意义上,咱们说GET是安全的(不是被密码学或者数据保护意义上的安全)。由于GET是安全的,因此GET返回的内容能够被浏览器,Cache服务器缓存起来。

而POST的语意是对指定资源“追加/添加”数据,因此是不安全的,每次提交的POST,参与的代码都会认为这个操做会修改操做对象资源的状态,因而,浏览器在你按下F5的时候会跳出确认框,缓存服务器不会缓存POST请求返回内容。

2)   ifModified参数:经过ifModified参数提升请求性能(即:“条件GET”:Last-Modified / If-Modified-Since和ETag / If-None-Match)

当你请求的资源并非一层不变的时候,即不能简单的一直使用客户端缓存时,你可能经过将cache设置为false来发送请求,这其实是在url加上时间戳组合成新的url,每次发送新的请求,这明显加大了服务器的压力。

对于这种状况,咱们能够经过ifModified参数改进缓存方式(即:cache和ifModified都设置为true),仅在请求的数据改变时从新获取。经过这种方式请求的url不会改变,而且每次都会发送到服务器,只是会有检验方法验证是否须要从新获取数据从而节省带宽和开销。

更多ETag描述(优势,解决了Last-Modified没法解决的一些问题,什么场合不该该被使用)

过程以下:

a)   将$.ajax()函数的cache和ifModified参数同时设置为true

b)   客户端请求服务端A,在服务端加上Last-Modified/ETag响应体一块儿返回。

c)   客户端缓存接收到的Last-Modified/ETag响应体,并在下一次发生请求A时将缓存的Last-Modified/ETag值作为If-Modified-Since/IF-None-Match请求头一块儿发给服务器。

d)   服务器接收If-Modified-Since/IF-None-Match后,就根据参数值检验自上次客服端请求以后资源是否有改动

  1.                           i.      若还未改动则直接返回响应304和一个空的响应体。
  2.                         ii.      若已改动则从新处理数据,返回最新的请求数据。

e)   这样,既保证不向客户端重复发出资源,也保证当服务器有变化时,客户端可以获得最新的资源。

这一过程当中,咱们只须要作:服务器返回Last-Modified/ETag响应头和在服务端检验数据是否失效并采起对应处理方式。其他步骤由jQuery框架的ajax()函数完成。

关键代码以下:   

客服端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$( '#btn_nowTime_long3' ).bind( 'click' , null
      , function  () {
      $.ajax( 'AjaxHandler.ashx?func=GetServerTime4Modified' ,
              {
                  type: 'get' ,
                  dataType: 'text' ,
                  cache: true ,
                  ifModified: true ,
                  success: function  (data) {
                      if  (data)
                          alert(data);
                  },
          });
  });

服务端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if (!String.IsNullOrEmpty(context.Request.Headers[ "If-Modified-Since" ]))
{
     if  (CheckResourceValidate())  // 检查资源有效性
     {
         // 若是资源有效,则直接返回304状态码,客户端回去到此状态码后会从缓存中取值。
         context.Response.StatusCode = 304;
 
         return ;
     }
}
// 请求数据
GetServerTimeAfter2Second();
context.Response.Cache.SetExpires(DateTime.Now.AddSeconds(5));
// 设置Last-Modified响应体
context.Response.Cache.SetLastModified(DateTime.Now);
  1. 跨域请求

在JavaScript中,有一个很重要的安全性限制,被称为“Same-Origin Policy”(同源策略)。这一策略对于JavaScript代码可以访问的页面内容作了很重要的限制,即JavaScript只能访问与包含它的文档在同一域下的内容。所谓同源是指,域名(host),协议(protocol),端口(port)相同。   

URL

说明

是否容许通讯

可否经过javascript解决

http://www.a.com/a.js

http://www.a.com/b.js

同一域名下

容许

 

http://www.a.com/lab/a.js

http://www.a.com/script/b.js

同一域名下不一样文件夹

容许

 

http://www.a.com:8000/a.js

http://www.a.com/b.js

同一域名,不一样端口

不容许

http://www.a.com/a.js

https://www.a.com/b.js

同一域名,不一样协议(http和https)

不容许

不能

http://www.a.com/a.js

http://70.32.92.74/b.js

域名和域名对应ip

不容许

http://www.cnblogs.com/a.js

http://www.a.com/b.js

http://script.a.com/b.js

http://a.com/b.js

不一样域名(host)

不容许

1)  $.ajax()为咱们提供了两种解决方案,不过都是只支持get方式,分别是jQuery的jQuery.ajax“jsonp”格式和jquery.getScript()(即jQuery.ajax “script”格式)方式。

2)   $.ajax()跨域原理分析

因为javascript的安全限制“同源策略”,因此咱们没法使用XMLHttpRequest直接请求别的域名下的资源。不过拥有src属性和href属性的<script>\<img>\<iframe>和<link>\<a>标签不受同源策略影响。$.ajax()提供的两种解决方案正是应用了动态建立<script>的方式来实现(即:生成<script>标签,src引入脚本,而后执行,最后移除<script>标签)。

3)   jQuery.ajax()的jsonp和script方式的异同点:

a)   相同:都走$.ajax() script格式的流程;不会触发全局事件和局部事件;只支持GET方式(POST请求会自动转化为GET请求);默认不启用缓存(cache:false)

b)   不一样:jsonp方式能够经过jsonp和jsonpCallback参数指定一个特定回调函数。

4)   示例部署说明:

    由于是跨域请求,因此须要在本机部署两个示例程序以模拟不一样域之间的访问,而且在示例代码中须要修改“crossUrl”为目的域路径。

5)   jsonp示例代码:

客服端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
     // jsonp方式跨域请求(dataType:jsonp)
     $( '#btn_cross_req1' ).bind( 'click' , null
         , function  () {
             $.ajax(crossUrl,
                 {
                     type: 'get' ,
                     dataType: 'jsonp' ,
                     jsonp: 'jsonpParamName' ,
                     jsonpCallback: 'crossCallback' ,
                     crossDomain: true ,
                 });
     });
function  crossCallback(data) {
     alert( 'jsonp'  + data);
}

        服务端:

1
2
3
4
context.Response.ContentType = "text/plain" ;
string  jsonpCallbackName = reqCollection[ "jsonpParamName" ];
context.Response.Write(String.Format( "{0}('来自域:{1}的相应信息')"
                 , jsonpCallbackName, context.Request.Url.Host));

    分析:

a)   因jsonp和jsonpCallback参数而改变的url以下。(即默认为:callback=jQuery随机值,更改成:jsonpParamName=crossCallback)

URL:http://192.168.1.100:6567/AjaxHandler.ashx?func=CrossRequest&jsonpParamName=crossCallback&_=1368360234428

b)   服务器端获取到jsonp回调函数名后,返回一个函数表达式。

6)   在XMLHttpRequest Level 2中新增了跨域访问方式、接收二进制等新功能,详细请看:XMLHttpRequest2 新技巧

 

最后,再来一张示例截图吧!!!

示例源码:触碰jQuery:AJAX异步详解.rar

 

 

 

 

 

 

本篇博文到此结束,主要介绍内容是使用XMLHttpRequest实现ajax请求和XMLHttpRequest Level 2为咱们所带来的改进,最后重点讲解了jQuery中经过$.ajax()方法实现ajax以及各个参数的详细介绍,并立举了经典示例说明了:跨域请求、ajax全局事件、ajax局部事件、xhr二进制数据处理、如何高效使用缓存……

作为一个后台工程师,你是否想深刻了解一些前台必须的技术呢?是的,我想了解,而且会慢慢把所了解到的技术以博文的方式整理分享给你们。

谢谢你们查阅,若是以为文章不错,还请多多帮推荐……

 

 

 

 

文中出现比较多的相关资源连接,这里整理下方便你们往后快速找到连接:

1)   jQuery相关

        jQueryAPI文档

        jQuery百度百科(Eg:模块,历史版本)

Ajax 技术资源中心(IBM)

这是有关 Ajax 编程模型信息的一站式中心,包括不少文档、教程、论坛、blog、wiki 和新闻。任何 Ajax 的新信息都能在这里找到。

jQuery.ajax()中的预过滤器和分发机制函数inspectPrefiltersOrTransports详解

jQuery的deferred对象详解

$.param()深度递归详解

2)   XMLHttpRequest Level 2 的新功能相关

        XMLHttpRequest 加强功能

        XMLHttpRequest Level 2 使用指南

        XMLHttpRequest2 新技巧

3)   跨域请求相关

JavaScript跨域总结与解决办法

总结了5种js跨域方式:利用<iframe>标签和document.domain属性、动态建立scrip、利用<iframe>标签和location.hash属性、window.name实现的跨域数据传输、使用HTML5 postMessage、利用flash跨域

域名和IP地址及域名解析

xhr注入_百度百科

        说说JSON和JSONP

4)   HTTP相关

HTTP深刻浅出 http请求

1)   介绍了一次HTTP通讯的7个步骤:创建TCP链接、Web浏览器向Web服务器发送请求命令、Web浏览器发送请求头信息、Web服务器应答、Web服务器发送应答头信息、Web服务器向浏览器发送数据、Web服务器关闭TCP链接

2)   介绍HTTP请求格式

        HTTP GET和POST的区别

HTTP 头部详解

        HTTP Content-type对照表

        格式:Content-Type: [type]/[subtype]; parameter

        HTTP状态码一览表(HTTP Status Code)   

    5)Jquery其余部分

        不定义JQuery插件,不要说会JQuery

相关文章
相关标签/搜索