1. 程式人生 > >AJAX的實現原理以及封裝

AJAX的實現原理以及封裝

       作為一名擼啊擼玩家,Ajax的中文名,讓我不禁想起了當年在S3賽季威風凜凜的武器大師,賈克斯!
       難得這份熟悉感,學好AJAX(阿賈克斯),應該不是難事。

       下面言歸正傳: 那何為AJAX?

       首先我們從名字入手,

       AJAX = Asynchronous JavaScript and XML(非同步的 JavaScript 和 XML)。

       非同步,JS,XML,這幾個詞我們都認識,又或者聽說過,這樣一來,我們是不是可以大膽地能推測出AJAX並非一種新的程式語言?

       沒錯,騷年,正是如此!

       這只不過是新罐子裝舊藥,一種使用現有標準的新方法。而它的作用,是在不重新載入整個頁面的情況下,能夠與伺服器交換資料並更新部分網頁。

       用W3School裡面的話來說,這是一種藝術。

       好比git提交東西時,沒有提示便是最好的提示,這更是一種哲理思想。

       滿分!

       其實AJAX內部實現並不麻煩,主要通過一個叫XMLHttpRequest的物件,而這個物件在現有的瀏覽器均被支援。

       可以說,它是整個AJAX實現的基礎,是瀏覽器用於後臺與伺服器交換資料的物件,有了它,才有了AJAX,也便有了部分頁面重新整理的藝術!

       建立 XMLHttpRequest 物件的語法很簡單,如下:

        var xhr=new XMLHttpRequest();  

       有了這個物件,我們就能使用其自身攜帶的方法,來做到與伺服器互動資料。

       傳送請求的方法必不可少:send();
       但在傳送之前,是不是得規定一下請求裡面的東西, 於是有了open();方法。
       兩語法如下:

        xhr.open("GET","test1.txt",true);
        xhr.send();
        這是具體的引數描述:
        open(method
,url,async):規定請求的型別、URL 以及是否非同步處理請求。 method:請求的型別;GETPOST url:檔案在伺服器上的位置 asynctrue(非同步)或 false(同步)
        send(string): 將請求傳送到伺服器。
        string:僅用於 POST 請求

       至於GET與POST,該如何選擇?下面引用W3School 的一段話:

與 POST 相比,GET 更簡單也更快,並且在大部分情況下都能用。

然而,在以下情況中,請使用 POST 請求:
無法使用快取檔案(更新伺服器上的檔案或資料庫)
向伺服器傳送大量資料(POST 沒有資料量限制)
傳送包含未知字元的使用者輸入時,POST 比 GET 更穩定也更可靠

       GET與POST請求本身也是一個不小的知識點,請自行學習,起碼得了解,GET請求,引數是拼接到url上面;而POST請求需要設定請求頭,用來傳遞引數,不然下面的封裝,會有點煩躁。

       傳送請求就緒,接下來是響應。當請求被髮送到伺服器時,我們需要執行一些基於響應的任務。
       在客戶端能做的事情不多,無非就是看一下自己的請求狀態,再監聽一下伺服器響應回來的東西,從而進行判斷,做出處理。
       請求狀態如何,可以通過XMLHttpReques物件的readyState屬性的值來檢視,分為:

0: 請求未初始化
1: 伺服器連線已建立
2: 請求已接收
3: 請求處理中
4: 請求已完成,且響應已就緒

       那這請求狀態值有什麼用呢?
       它是以其中一個判斷條件的作用存在,只有當狀態值為4時,才證明響應的資料被解析完成,返回給客戶端。
       而每當 readyState狀態值被改變時,就會觸發一個叫 onreadystatechange 事件,這個事件是XMLHttpRequest物件的一個屬性。
       onreadystatechange 事件一共會被觸發 5 次(0 - 4),對應著 readyState 的每個變化。
        所以說,只要當狀態值為4時,我們就可以獲得響應回來的資料。
       但是剛才說了,狀態值只是作為其中的一個判斷條件,還有一個判斷條件是監聽伺服器的狀態碼。

        status  
            200: 表示"OK"
            404: 表示未找到頁面

        這個狀態碼是在伺服器連線建立的時候就能監聽到(readyState狀態值為1的時候)。具體的工作流程,請下面的圖示:
這裡寫圖片描述

        到這一步,readyState為4 且status為200時,我們已經進入到拿資料的環節。
        至於怎麼拿資料?更簡單,通過XMLHttpRequest的兩個屬性。

        responseText :獲得字串形式的響應資料。
        responseXML:獲得 XML 形式的響應資料。

        輾輾轉轉,終於到了封裝的重頭戲。這次不廢話,直接上程式碼,原理都在上面了,註釋會簡單備註一下。

var $={
    /*傳遞引數物件,返回拼接之後的字串*/
    /*{‘name’:’jack,’age’:20}=>  name=jack&age=20&*/
    getParmeter:function(data){
        var result="";
        for(var key in data){
            result=result+key+"="+data[key]+"&";
        }
        /*將結果最後多餘的&擷取掉*/
        return result.slice(0,-1);
    },
    /*實現ajax請求*/
    ajax:function(obj){
        /*1.判斷有沒有傳遞引數,同時引數是否是一個物件*/
        if(obj==null || typeof obj!="object"){
            return false;
        }
        /*2.獲取請求型別,如果沒有傳遞請求方式,那麼預設為get*/
        var type=obj.type || 'get';
        /*3.獲取請求的url  location.pathname:就是指當前請求發起的路徑*/
        var url=obj.url || location.pathname;
        /*4.獲取請求傳遞的引數*/
        var data=obj.data || {};
        /*4.1獲取拼接之後的引數*/
        data=this.getParmeter(data);
        /*5.獲取請求傳遞的回撥函式*/
        var success=obj.success || function(){};

        /*6:開始發起非同步請求*/
        /*6.1:建立非同步物件*/
        var xhr=new XMLHttpRequest();
        /*6.2:設定請求行,判斷請求型別,以此決定是否需要拼接引數到url*/
        if(type=='get'){
            url=url+"?"+data;
            /*重置引數,為post請求簡化處理*/
            data=null;
        }
        xhr.open(type,url);
        /*6.2:設定請求頭:判斷請求方式,如果是post則進行設定*/
        if(type=="post"){
            xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
        }
        /*6.3:設定請求體,post請求則需要傳遞引數*/
        xhr.send(data);

        /*7.處理響應*/
        xhr.onreadystatechange=function(){
            /*8.判斷響應是否成功*/
            if(xhr.status==200 && xhr.readyState==4){
                /*客戶端可用的響應結果*/
                var result=null;
                /*9.獲取響應頭Content-Type ---型別是字串*/
                var grc=xhr.getResponseHeader("Content-Type");
                /*10.根據Content-Type型別來判斷如何進行解析*/
                if(grc.indexOf("json") != -1){
                    /*轉換為js物件*/
                    result=JSON.parse(xhr.responseText);
                }
                else if(grc.indexOf("xml") != -1){
                    result=xhr.responseXML;
                }
                else{
                    result=xhr.responseText;
                }
                /*11.拿到資料,呼叫客戶端傳遞過來的回撥函式*/
                success(result);
            }
        }

    }
};
呼叫方式與jquery類似的:
$.ajax({
    url:'',
    type:'',
    data: {},
    success:function(result){
        //code...
    }
});

        若是有誤人子弟的地方,務必指出,大謝大謝。
                                                                                ——龍貓村莊1號村民敬上!