1. 程式人生 > >電子商城後臺系統(四):改寫ajax請求函式

電子商城後臺系統(四):改寫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,在後面的頁面中,還有很多地方,會使用到這個變數。

在編碼的過程中,我的思想一直是:功能的實現,並不是編碼的結束,而是編碼的開始。所以我經常是,寫了幾十行程式碼,實現了一個功能,然後,我可以對這幾十行程式碼,一遍又一遍的修改,讓所寫的程式碼,更通用,更易用,更高效。寫一萬行普通的程式碼,不如寫一百行精煉的程式碼。