`
jljlpch
  • 浏览: 323992 次
  • 性别: Icon_minigender_1
  • 来自: 南昌
社区版块
存档分类
最新评论

jquery.ajax

阅读更多
7.2 jquery.ajax
                prk/彭仁夔  08-08-27
这所有的最终都是通过jQuery.ajax()来完成的。
ajax : function(s) {
	//两次继承s,以便在测试中能检测
	s = jQuery.extend(true, s, jQuery.extend(true, {}, 
jQuery.ajaxSettings,	s));         ①
	var jsonp, jsre = /=\?(&|$)/g, status, data,
 type = s.type	.toUpperCase();
// 如果不是字符集串就转换在查询字符集串
if (s.data && s.processData && typeof s.data != "string")
		s.data = jQuery.param(s.data);

// 构建jsonp请求字符集串。jsonp是跨域请求,要加上callback=?后面将会加函数名
if (s.dataType == "jsonp") {                               ②
if (type == "GET") {//使get的url包含 callback=?后面将会进行加函数名
		if (!s.url.match(jsre))
			s.url += (s.url.match(/\?/) ? "&" : "?")
							+ (s.jsonp || "callback") + "=?";
			} // 构建新的s.data,使其包含callback=function name
else if (!s.data || !s.data.match(jsre))
		s.data = (s.data ? s.data + "&" : "") + (s.jsonp||"callback")+ "=?";
s.dataType = "json";
}		
//判断是否为jsonp,如果是,进行处理。
if (s.dataType == "json"  
			&& (s.data && s.data.match(jsre) || s.url.match(jsre))) {③
	 jsonp = "jsonp" + jsc++;
/ /为请求字符集串的callback=加上生成回调函数名
	if (s.data)s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
	s.url = s.url.replace(jsre, "=" + jsonp + "$1");

			// 我们需要保证jsonp 类型响应能正确地执行
	//jsonp的类型必须为script。这样才能执行服务器返回的
	//代码。这里就是调用这个回调函数。
	s.dataType = "script";
//window下注册一个jsonp回调函数有,让ajax请求返回的代码调用执行它,
	//在服务器端我们生成的代码 如callbackname(data);形式传入data.
	window[jsonp] = function(tmp) {
		data = tmp;success();complete();
	// 垃圾回收,释放联变量,删除jsonp的对象,除去head中加的script元素
	   window[jsonp] = undefined;
		try {	delete window[jsonp];
			} catch (e) {	}
		if (head)	head.removeChild(script);
		};
	}

if (s.dataType == "script" && s.cache == null)	s.cache = false;
// 加上时间戳,可见加cache:false就会加上时间戳
if (s.cache === false && type == "GET") {
	var ts = now();
	var ret = s.url.replace(/(\?|&)_=.*?(&|$)/, "$1_=" + ts + "$2");
	// 没有代替,就追加在url的尾部
	s.url = ret+ ((ret == s.url) ? (s.url.match(/\?/) ? "&" : "?") + "_="
						+ ts : "");
	}
// data有效,追加到get类型的url上去
if (s.data && type == "GET") {
		s.url += (s.url.match(/\?/) ? "&" : "?") + s.data;
		// 防止IE会重复发送get和post data
		s.data = null;
		}
// 监听一个新的请求
if (s.global && !jQuery.active++) jQuery.event.trigger("ajaxStart");④
// 监听一个绝对的url,和保存domain
var parts = /^(\w+:)?\/\/([^\/?#]+)/.exec(s.url);
// 如果我们正在请求一个远程文档和正在load json或script通过get类型
//location是window的属性,通过和地址栏中的地址比较判断是不是跨域。
if (s.dataType == "script"	&& type == "GET"&& parts	&& (parts[1] && 
parts[1] != location.protocol || parts[2] != location.host)) {⑤
		// 在head中加上<script src=""></script>
		var head = document.getElementsByTagName("head")[0];
		var script = document.createElement("script");
		script.src = s.url;
		if (s.scriptCharset)	script.charset = s.scriptCharset;
		//如果datatype不是jsonp,但是url却是跨域的。采用scriptr的
		//onload或onreadystatechange事件来触发回调函数。
	   if (!jsonp) {
			var done = false;
			// 对所有浏览器都加上处理器
			script.onload = script.onreadystatechange = function() {
			if (!done&& (!this.readyState || this.readyState == "loaded" 
|| this.readyState == "complete")) {
					done = true;	success();
					complete();head.removeChild(script);
				}
		};
	}
	head.appendChild(script);
// 已经使用了script 元素注射来处理所有的事情
	return undefined;
}
var requestDone = false;
// 创建request,IE7不能通过XMLHttpRequest来完成,只能通过ActiveXObject
var xhr = window.ActiveXObject                               ⑥
		? new ActiveXObject("Microsoft.XMLHTTP"): new XMLHttpRequest();
// 创建一个请求的连接,在opera中如果用户名为null会弹出login窗口中。
if (s.username)xhr.open(type, s.url, s.async, s.username, s.password);
else	xhr.open(type, s.url, s.async);
// try/catch是为防止FF3在跨域请求时报错
try {// 设定Content-Type                                              ⑦
	if (s.data)
		xhr.setRequestHeader("Content-Type", s.contentType);
		// 设定If-Modified-Since
	if (s.ifModified)
		xhr.setRequestHeader("If-Modified-Since",
			jQuery.lastModified[s.url]|| "Thu, 01 Jan 1970 00:00:00 GMT");
// 这里是为了让服务器能判断这个请求是XMLHttpRequest
	xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
// 设定 Accepts header 。指能接收的content-type,在服务器端设定
	xhr.setRequestHeader("Accept", s.dataType && s.accepts[s.dataType]
			? s.accepts[s.dataType] + ", */*": s.accepts._default);
} catch (e) {}
//拦截方法,我们可以在send之前进行拦截。返回false就不send
if (s.beforeSend && s.beforeSend(xhr, s) === false) {         ⑧
	// 清除active 请求计数
	s.global && jQuery.active--;
	xhr.abort();
	return false;
}

// 触发全局的ajaxSend事件
if (s.global)	jQuery.event.trigger("ajaxSend", [xhr, s]);
// 等待response返回,主要是为后面setInterval用。
var onreadystatechange = function(isTimeout) {           ⑨
// 接收成功或请求超时
if (!requestDone && xhr&& (xhr.readyState == 4 ||isTimeout == "timeout")) {	requestDone = true;
		 //清除定时器
		if (ival) {clearInterval(ival);		ival = null;	}
	// 分析status:tiemout-->error-->notmodified-->success
	status = isTimeout == "timeout" ? "timeout" : !jQuery
		ttpSuccess(xhr) ? "error" : s.ifModified&& jQuery.
httpNotModified(xhr, s.url)	? "notmodified": "success";
    	//如果success且返回了数据,那么分析这些数据
	if (status == "success") {					
		try {	data = jQuery.httpData(xhr, s.dataType, s);
			 } catch (e) {	status = "parsererror";	}
	}
// 分析数据成功之后,进行last-modified和success的处理。				
	if (status == "success") {
		var modRes;
		  try {modRes = xhr.getResponseHeader("Last-Modified");
			} catch (e) {	//FF中如果head取不到,会抛出异常} 
		 //保存last-mordified的标识。
		if (s.ifModified && modRes)jQuery.lastModified[s.url] = modRes;
	   // JSONP 有自己的callback
	    if (!jsonp) success();
	} else	// 失败时的处理
	jQuery.handleError(s, xhr, status);
// 无论如何都进行cpmplate.timeout和接收成功
	complete();
if (s.async)	xhr = null; // 防内存泄漏
}
};
if (s.async) {
// 这里是采用poll的方式,不是push的方式
//这里为什么不采用onreadystatechange?
var ival = setInterval(onreadystatechange, 13);
//如果过了timeout还没有请求到,会中断请求的。
	if (s.timeout > 0)
		setTimeout(function() {					
			if (xhr) {	xhr.abort();
				if (!requestDone)	onreadystatechange("timeout");	}
		}, s.timeout);
	}
// 发送
try {xhr.send(s.data); catch(e){jQuery.handleError(s,xhr,null,e);} ⑩
// firefox 1.5 doesn't fire statechange for sync requests
if (!s.async)	onreadystatechange();
function success() {
	// 调用构建请求对象时指定的success回调。
	if (s.success)	s.success(data, status);
	// 执行全局的回调
	if (s.global)	jQuery.event.trigger("ajaxSuccess", [xhr, s]);
	}
function complete() {
	// 本地的回调
	if (s.complete)	s.complete(xhr, status);
	// 执行全局的回调
	if (s.global)	jQuery.event.trigger("ajaxComplete", [xhr, s]);
	// 全局的ajax计数器
	if (s.global && !--jQuery.active)jQuery.event.trigger("ajaxStop");
	}
// return XMLHttpRequest便进行about()或其它操作.
return xhr;
},
Jquery.ajax是大包大揽的非常复杂的一个方法。它并没有像其它的lib一样,把每个小部分都分开来。它是整个都整在一个函数中。看起来很多,实际上上也没有脱离前面所说的ajax的请求的五步。它的很大一部分代码在处理跨域请求的处理上。下面就分别就ajax的代码进行分析。
ajaxSettings
在①处通过继承的方式把传入参数s和默认的jQuery.ajaxSettings都clone到s变量中。S的同名属性会覆盖jQuery.ajaxSettings的同名属性。这里两次继承s,以便在测试中能检测。
//默认的ajax的请求参数
	ajaxSettings : {
		url : location.href,//默认是地址栏中url
		global : true,//默认支持全局的ajax事件
		type : "GET",
		timeout : 0,
		contentType : "application/x-www-form-urlencoded",	
	 processData : true,
		async : true,
		data : null,
		username : null,
		password : null,
		accepts : {
			xml : "application/xml, text/xml",
			html : "text/html",
			script : "text/javascript, application/javascript",
			json : "application/json, text/javascript",
			text : "text/plain",
			_default : "*/*"
		}
这是默认的ajax的设定,我们要在参数s设定同名的属性来覆盖这些属性。但是我们不能覆盖accepts。这个会在后面的代码用到。我们可以通过设定s.dataType等于accepts中的某一个属性key指定请求的data类型,如xml,html,script,json,text。dataType还支持默认的_default和跨域的jsonp。不过其最终会解析成script。
scriptTag
②~⑥是处理跨域请求的部分。对于dataType为jsonp的类型,给其请求的字符串(可能是s.data)加上callback=callbackfn的key/value串,然后在window下注册一个callbackfn的函数。这个函数的形式如callbackfn(data){ data = tmp;success();complete();}。它代理了通过ajax(s)的传入s参数中success();complete()的功能。它就是调用这个函数,实际上是调用success();complete()的函数。
那么怎么调用呢?ajax不支持跨域。在⑤处,我们可以看到这里是采用scriptTag的方式来完成。先在页面的<head>中添加一个<script src=url />的标签。因为在<head>中。浏览器会自动载入并运行请求返回的script。如果是jsonp的形式,服务器端还要动态生成的content-type为script的代码:callbackfn(data);只有这样才会调用在window中注册的函数callbackfn。同时传入所需要的参数。
如dataType == "script"形式的跨域,那只能是通过script.onload 或 script.onreadystatechange事件来触发回调。这里我们可以通过服务器返回的script代码:var data=xxx。来传递参数给s.success();s.complete()。Jquery这里采用是全局变量data来进行操作的。
Ajax Event
④是采用了jQuery.event.trigger("ajaxStart");来触发全局的ajaxStart事件。这也是说只要注册了这个事件的元素,在任何的ajax的请求时ajaxStart都会执行元素注册的事件处理函数。这和Ext的事件有点相似。但是它不是全局的。
jQuery.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","), function(i, o) {
	jQuery.fn[o] = function(f) {// f:function
		return this.bind(o, f);
	};
上面的代码是为jquery对象注册了ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend这几种ajax的事件方法,在jquery.ajax中不同的时刻都会触发这些事件。当然我们也可以采用s.global=false来设定不触发这些事件。
因为这是全局的,个人认为其设计的目的就是为了在这些时候能以某种形式来告诉用户ajax的进行的状态。如在ajaxstart的时候,我们可能通过一个topest的div层(加上遮罩的效果)的元素注册一个ajaxstart事件的处理方法。该方法就是显示这个层和显示“你的数据正在提交。。。”这个的提示。这是这6种事件的最佳用法了。
如果进行私有处理,那么要在事件的处理函数中进行判断。因为每个事件处理函数的第二参数是jquery.ajax(s)的s参数。我们可以在这个参数中做私有的标识,如eventType:xxx。每类不同的请求有不同的eventType值。在事件处理函数再根据这个eventType==xxx进行判断,从而进行私有的处理。如果有大量的这样的私有处理也是会影响ajax的效率的。
setRequestHeader
⑥处是创建一个xhr对象并通过open来创建一个连接(socket)。
⑦处是设定请求的头部(setRequestHeader)。如果data的存在的话,那就得设定Content-Type,便于服务器按一定的规则来解码。可以看出post的方式通过data传递数据要安全一点。
那么服务器如果区别这个请求是ajax呢?因为同步和异步ajax的请求的头文件是一样的。我们如果通过X-Requested-With"="XMLHttpRequest”来标识这个请求是ajax的请求。如果服务器硬是要区分的话,就可以通过获取该头部来判断。
在头部的定义中,还可能通过Accept来指定接受的数据的类型,如application/xml, text/xml", "text/html", "text/javascript, 等等。
头部还有一个If-Modified-Since的属性用来提高效率的。它和”Last-Modified配合起来使用。在浏览器第一次请求某一个URL时,服务器端的返回状态会是200,内容是你请求的资源,同时有一个Last-Modified的属性标记此文件在服务期端最后被修改的时间,格式类似这样:Last-Modified: Fri, 12 May 2006 18:53:33 GMT 
客户端第二次请求此URL时,根据 HTTP 协议的规定,浏览器会向服务器传送 If-Modified-Since 报头,询问该时间之后文件是否有被修改过:  If-Modified-Since: Fri, 12 May 2006 18:53:33 GMT    如果服务器端的资源没有变化,则自动返回 HTTP 304 (Not Changed.)状态码,内容为空,这样就节省了传输数据量。
当服务器端代码发生改变或者重启服务器时,则重新发出资源,返回和第一次请求时类似。从而保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。
拦截处理
⑧处是一个send之前的拦截处理,可以通过s. beforeSend(xhr, s)函数的形式传入拦截函数。保证在发送之前确保满足某些条件。在取得返回数据的时候,也可以通过s.dataFilter(data, type);形式来拦截处理data。不过这里主要的作用对data进一步的筛选。
onreadystatechange
⑨处是onreadystatechange的回调处理。这里采用是poll的形式进行处理。它把返回的状态分成status:tiemout-->error-->notmodified-->success—>parsererror这几种。如果status == "success"那么分析这些数据之后再进行last-modified相关的处理。为了不取回没有修改过数据。
分析数据的代码如下:
//处理请求返回的数据
	httpData : function(xhr, type, s) {
		var ct = xhr.getResponseHeader("content-type"), 
		  xml = type == "xml"	|| !type && ct && ct.indexOf("xml") >= 0, 
		   data = xml? xhr.responseXML	: xhr.responseText;
		if (xml && data.documentElement.tagName == "parsererror")
			throw "parsererror";
		//允许一个pre-filtering函数清洁repsonse		
		if (s && s.dataFilter)
			data = s.dataFilter(data, type);
				//script时,就运行
		if (type == "script")	jQuery.globalEval(data);
		//json,生成json对象。
		if (type == "json")		data = eval("(" + data + ")");
		return data;
	},
如果返回的content-type是xml,html,text等都返回。对script执行jQuery.globalEval来执行它。对于Json类型,通过eval来生成返回的json对象。
// 在全局的范围eval 代码,也就是在<head></head>中
globalEval : function(data) {
	data = jQuery.trim(data);
		if (data) {
// Inspired by code by Andrea Giammarchi
// http://webreflection.blogspot.com/2007/08/
//global-scope-evaluation-and-dom.html
	var head = document.getElementsByTagName("head")[0]
						|| document.documentElement,
		script = document.createElement("script");
	script.type = "text/javascript";
	if (jQuery.browser.msie)	script.text = data;
	else	script.appendChild(document.createTextNode(data));

	// Use insertBefore instead of appendChild to circumvent an IE6
	// bug. This arises when a base node is used (#2709).
		head.insertBefore(script, head.firstChild);
		head.removeChild(script);
			}		},
				

 

分享到:
评论

相关推荐

    jquery.ajax-combobox, jQuery插件,创建一个文本框,可以以自动完成并下拉选择.zip

    jquery.ajax-combobox, jQuery插件,创建一个文本框,可以以自动完成并下拉选择 jquery.ajax-combobox 可以自动完成和pull-down-select的文本框的jQuery插件。 演示http://www.usamimi.info/~sutara/ajax-combobox

    jquery.ajaxupload.js

    AjaxUpload.js 就是一个js文件,里面封装了上传文件的代码,其实就是一个js的框架,利用它来更简单的实现文件的上传

    JQuery.Ajax之错误调试帮助信息

    JQuery.Ajax之错误调试帮助信息

    ajax传11值,jQuery.ajax,json格式转化和前台后台传值.docx

    .ajax传11值,jQuery.ajax,json格式转化和前台后台传值.docx

    ajax传11值,jQuery.ajax,json格式转化和前台后台传值.pdf

    .ajax传11值,jQuery.ajax,json格式转化和前台后台传值.pdf

    Jquery.Pagination.js + Jquery.Ajax + ASP.NET----无刷新分页Pagination 1.5.1

    Jquery.Pagination.js + Jquery.Ajax + ASP.NET----无刷新分页Pagination 1.5.1,是在原作者基础上修改的,因为Pagination 1.5.1与它的低版本有很大的区别,所以在此实例中增加了新版的使用方法

    jQuery.ajax()

    jQuery 底层 AJAX 实现。简单易用的高层实现见 $.get, $.post 等。$.ajax() 返回其创建的 XMLHttpRequest 对象。大多数情况下你无需直接操作该函数,除非你需要操作不常用的选项,以获得更多的灵活性。 最简单的...

    jQuery.XDomainRequest.js

    Implements automatic *Cross Origin Resource Sharing* support using the `XDomainRequest` object for IE8 and IE9 when using the [$.ajax](http://api.jquery.com/jQuery.ajax/) function in jQuery 1.5+. ...

    jquery.ajax+php制作帝国6.6~7.2检测会员名是否可注册插件源码

    在这个插件中,jQuery的`$.ajax()`是实现AJAX的核心工具。 3. **PHP**:PHP是一种广泛使用的开源服务器端脚本语言,特别适合Web开发。在这个插件中,`ajax_user.php`文件很可能是处理来自前端AJAX请求的后端逻辑。...

    jquery.unobtrusive-ajax.rar

    这个库利用数据属性(data-* attributes)和jQuery事件来实现Ajax功能,使得页面的异步更新更加优雅和易于维护。 在传统的Web开发中,Ajax通常需要在JavaScript代码中添加大量细节,而jQuery Unobtrusive Ajax通过...

    jquery.unobtrusive-ajax.min.js

    Ajax.BeginForm 提交,需要引用此文件才会执行OnSuccess

    jquery1.9.1 支持低版本ajax (ajax前jQuery.support.cors=true )

    jquery1.9.1 支持低版本ajax (ajax前jQuery.support.cors=true )

    jQuery.Ajax()的data参数类型详解

    在jQuery的Ajax方法中,`data`参数是一个非常关键的部分,它用于传递要发送到服务器的数据。本篇文章将深入探讨`data`参数的不同类型及其使用方法。 首先,`data`参数可以接受多种类型的数据,包括JavaScript对象、...

    Jquery.json.js

    在Web开发中,jQuery经常用于与服务器进行异步通信(Ajax),而JSON作为数据交换格式,常常是Ajax通信中的数据载体。jQuery提供了方便的方法来处理JSON数据,包括`$.getJSON()`和`$.ajax()`等函数,可以方便地从...

    ajaxFileUpload 报这错jQuery.handleError is not a function

    然而,从jQuery 1.8版本开始,这个方法已被废弃,取而代之的是使用`$.ajax.error`或新的Promise API中的`.fail()`方法来处理错误。 解决这个问题的方法有几种: 1. **回退jQuery版本**:如果你的应用程序依赖于`...

    jquery.paginate.js

    《jQuery.paginate.js插件详解及其应用》 在网页开发中,当数据量过大时,分页功能就显得尤为重要,它能帮助用户更好地浏览和管理大量信息。jQuery是一个广泛使用的JavaScript库,它提供了丰富的功能来简化DOM操作...

    jquery.min.js,很好用的基础插件

    5. **AJAX(Ajax)**:jQuery的`.ajax()`方法封装了XMLHttpRequest,使得异步数据交互更为便捷,同时提供了`.get()`, `.post()`等简化的接口。 6. **链式调用(Chaining)**:jQuery的每个方法返回的都是jQuery对象...

    jquery-1.12.4-jquery.min.js.zip

    4. **Ajax交互**:jQuery的`.ajax()`方法是进行异步数据交互的标准方式,它可以处理XMLHttpRequest的所有细节,如`$.ajax({url: "data.json", type: "GET", success: function(data) { ... }})`,用于从"data.json...

    jquery.ajax.progress:允许将事件处理程序绑定到 XHR2 上传下载进度事件

    jquery.ajax.progress 允许将事件处理程序绑定到 XHR2 上传/下载进度事件。 基于 nebirhos 脚本 ( ) 这些事件是: downloading和uploading downloading事件的示例代码: var jqXHR = $ . get ( '...

    jquery-ajax实例

    在JavaScript的世界里,jQuery是一个非常流行的库,它极大地简化了DOM操作、事件处理以及Ajax交互。本实例聚焦于"jQuery-AJAX",这是一项核心功能,用于在不刷新整个页面的情况下与服务器交换数据并更新部分网页内容...

Global site tag (gtag.js) - Google Analytics