电子商城后台系统(四):改写ajax请求函数

ajax请求,是局部刷新,页面不一定会跳转。这就面临着一个问题,如果用户的网络出现波动或是网络慢,就可能会出现用户多次点击,造成重复请求的问题。解决方法,可以在用户点击了按钮之后,先禁用按钮,等ajax请求响应了之后,再让按钮恢复可用状态。但是如果网站里ajax请求很多的话,这样做,就有点不合适了。

一开始,我的想法是,能不能封装一个函数,所有的ajax请求都由这一个函数来发送,然后在这个ajax请求里面做一些处理,这样就可以解决重复请求的问题。于是就有了下面的函数

function sendAjax(ajaxContent){
	$('#king_mask').show;
	var success = ajaxContent.success;
	ajaxContent.success = function(data){
		$('#king_mask').hide();
		success(data);
	};
	$.ajax(ajaxContent);
}

然后,页面所有的ajax请求,都不再使用$.ajax函数来发送,改用sendAjax函数来发送,参数和$.ajax函数一样,接收一个json对象。#king_mask,就是一个div,一个盖住了整个页面的遮罩层。这个方法就比较简单了,是最原始的封装。使用这个方法,需要别人在自己的页面创建一个#king_mask的div,使用起来不方便。而且如果别人所有的页面都已经写好了,后面再使用这个方法,意味着要把代码里所有的$.ajax改成sendAjax,工作量可能就比较大,而且,通常程序员都不愿意干这一类事情。

我们在设计方法的时候,都要尽量地做到非侵入。所谓的非侵入,就是别人使用你写好的方法,原先的代码,不用动,如果哪一天,不想用你写的方法了,只要把你的方法删除,代码也不用动,功能还能正常运行。基于这样的思想,再改写这个函数,把#king_mask放到js中来维护。同时,在上面的函数内,通过改写ajaxContent的success,可以让ajax请求响应成功后,隐藏遮罩层,那在外层,为什么不可以改写$.ajax函数呢?基于这样的想法,代码更改如下

(function(){
	//页面加载完成后,把遮罩层添加进页面
	$(function(){
		$('<div id="king_mask"></div>')
		.css({'background-color':'black','position':'absolute','left':'0','top':'0','opacity':'0.2','z-index':'99999'})
		.appendTo($('body'));
	});
	
	//改写$.ajax函数
	var fun = $.ajax;
	$.ajax = function(ajaxContent){
		//让遮罩层的宽高等于文档的宽高,因为文档的宽高,随时可能会变,所以每次就重新赋值,并显示出来
		$('#king_mask').width($(document).width()).height($(document).height()).show();
		var success = ajaxContent.success;
		var error = ajaxContent.error;
		ajaxContent.success = function(data){
			$('#king_mask').hide();
			success(data);
		}
		ajaxContent.error = function(data){
			$('#king_mask').hide();
			error(data);
		}
		fun(ajaxContent);
	}
})()

这样一来,别人使用这个方法,就不用关心遮罩层的创建了,也不用改写方法,直接像以前一样,使用$.ajax函数发送ajax请求,就可以了。现在新的问题是,如果用户的网络很慢,甚至后面直接断掉了网,这个时候,ajax请求就不会有响应了,也就意味着遮罩层会一直盖在页面上,这样就不好了。简单点做,可以给ajax请求设置一个超时时间,超过这个时间没有响应就会走error函数。简单的方法,我肯定不会用的。。。

我的做法是,设置一个超时时间,如果用户在超时时间之前,点击遮罩层,是没有反应的,在超时时间之后,用户点击遮罩层,会取消ajax请求,并同时给出一个提示语“请求数据失败,请重试!”,这样一来,可以把超时时间设置的比较小,然后依据用户的忍耐度不同,在超时时间过后,随时可以点击遮罩层,取消ajax请求的发送。最终的代码

(function(){
	//声明一个全局的变量domain,用来存放一些配置信息
	window.domain = {};
	//ajax超时时间,在超时时间之内,点击遮罩层,不会有任何反应。超时时间之后点击,会取消ajax请求
	domain.ajaxTimeout = 2000;
	//页面加载完成后,创建遮罩层,并添加进页面
	$(function(){
		$('<div id="king_mask"></div>')
		.css({'background-color':'black','position':'absolute','left':'0','top':'0','opacity':'0.2','z-index':'99999'})
		.appendTo($('body'))
		.click(function(){
			//遮罩层的点击事件,domain.flag为真,并且domain.xhr(ajax请求对象)不为空,才会取消ajax请求。
			if(domain.flag && domain.xhr){
				domain.xhr.abort();
				domain.xhr = null;
				$('#king_mask').hide();
				alert("请求数据失败,请重试!");
			}
		});
	});
	
	//改写$.ajax函数
	var fun = $.ajax;
	$.ajax = function(ajaxContent){
		//让遮罩层的宽高等于文档的宽高,因为文档的宽高,随时可能会变,所以每次就重新赋值,并显示出来
		$('#king_mask').width($(document).width()).height($(document).height()).show();
		//设置一个一次性的定时器,在超时时间过后,将domain.flag更改为true,这样遮罩层的点击事件,就满足一个条件了
		domain.timer = setTimeout(function(){domain.flag = true;}, domain.ajaxTimeout);
		var success = ajaxContent.success;
		var error = ajaxContent.error;
		ajaxContent.success = function(data){
			clearTimeout(domain.timer);
			domain.flag = false;
			domain.xhr = null;
			$('#king_mask').hide();
			success(data);
		}
		ajaxContent.error = function(data){
			clearTimeout(domain.timer);
			domain.flag = false;
			domain.xhr = null;
			$('#king_mask').hide();
			//data.readyState为4,代表是服务器响应的错误,执行原先的error函数,
			//否则,就代表是用户点击了遮罩层,取消的ajax请求,那就啥也不做
			if(data.readyState == 4){
				error(data);
			}
		}
		//使用原先的ajax发送函数发送ajax请求,并把ajax请求对象,赋值给domain.xhr
		domain.xhr = fun(ajaxContent);
	}
})()

代码并不多,逻辑应该也不算复杂吧。这里使用了一个全局的变量——domain,在后面的页面中,还有很多地方,会使用到这个变量。

在编码的过程中,我的思想一直是:功能的实现,并不是编码的结束,而是编码的开始。所以我经常是,写了几十行代码,实现了一个功能,然后,我可以对这几十行代码,一遍又一遍的修改,让所写的代码,更通用,更易用,更高效。写一万行普通的代码,不如写一百行精炼的代码。

猜你喜欢

转载自blog.csdn.net/kingzhsh/article/details/85039392
今日推荐