jQuery源碼分析系列(30) : Ajax 總體結構

開頭引用一段javascript

想起一句話:前端研究,研究個屁~ 的確如此呀。補充下聯:前端設計,設計個屁~

前端目前最大的困境是,如 HTML 同樣,不管你承不認可,市場上並不太須要 HTML 高手

其實這裏引起一個問題:前端的價值到底是什麼?將來應該如何發展?php

我我的以爲仍是一個核心價值的問題,前端在漂亮的東西都是須要後端的數據支撐的,並且前端的絕大部分問題,其實都須要後端才能解決,就如我開發了三年的混合項目,雖然前端代碼有3萬行,可是後端一個數據拷貝失敗,整個項目都是白搭css

固然這裏我並不是要深刻這個話題,只是想代表儘量的提升自身的價值html

從前端的歷史變動與發展過程來看,若是拿人類的歷史來比喻,從最原始的刀耕火種以HTML靜態結構爲主的原始社會,到後來帶有邏輯處理與服務器混搭交互的的石器時代以及最近幾年流行的node.js,MVC,MVVM,Phonegap等衍生而來的東東讓前端大躍進式的跳躍進入了一個新的工業時代,不到20年的時間web技術翻天覆地的變化前端

現在的前端進入了 MV* 時代,同時Ajax也帶來了SPA,Node帶來了全棧,這些都切實推進着前端往前發展java

優秀的前端一方面是完成的效率,另外一方面是可維護和可擴展性的提升帶來的潛在價值,解放生產力,專一展示與業務邏輯,減小瑣碎的兼容處理node

若是你使用一面大鏡子做爲衝浪板會發生什麼?或許你會在較短的時間內征服海浪,可是你確定從心裏深處明白,這不是衝浪的正確選擇jquery

因此咱們不該該只要求本身僅僅停留在API的層次,若是能理解原理深刻設計,那麼就將會跨上一個新的臺階css3

 


jQuery.Ajax作了那些事?web

咱們知道AJAX的底層實現實際上是很簡單的.拋開IE不說,標準的w3c直接提供了XMLHttpRequest方法

關於AJAX基礎請飛機 觸碰jQuery:AJAX異步詳解

咱們主要站在設計的角度理解,如何設計出低耦合高內聚的代碼

jQuery對Ajax的處理主要體如今對瀏覽器兼容,數據的處理及過濾,各類事件的封裝上

主要有如下幾部分擴展:

提供快捷接口

提供底層接口

提供數據序列化

提供全局Ajax事件處理

具體使用請看API,這裏再也不重複

 


分析下面一個demo

給document綁定ajaxStart,ajaxComplete回調事件

trigger綁定一個點擊事件,發送ajax請求

點擊trigger出發點以後,發送一個ajax請求,而且經過complete,done,ajaxStart, ajaxComplete返回狀態回調

//全局事件觸發
$(document).ajaxStart(function() {
    console.log(arguments)
}).ajaxComplete(function() {
    $(".log").text("Triggered ajaxComplete handler.");
});


$(".trigger").click(function() {
    //發送ajax請求
    //
    $.ajax({
        url: "php.html",
        context: document.body,
        complete: function() {
            console.log(this)
        }
    }).done(function() {
        console.log(this)
    });
});

這裏實現比較特別的地方

針對ajax提供2種回調方式,內部的complete回調與外部的done回調

全局document上都能捕獲到ajax的每一步的回調通知

換句話說,針對ajax的請求,每一步的狀態,成功或者失敗,咱們有3種方式能夠獲取,可是每一種仍是有各自的區別

1 ajax的參數回調

2 基於deferred方式的done回調

3 全局的的自定義事件的回調

 


從設計的層面上來考下,這種事件組合的方式是如何實現?有什麼優點?

設計一:

tAjax({
    url: "php.html",
    complete: function(data) {
        console.log(data)
    }
})

若是要實現這種接口調用

那麼咱們就須要封裝下代碼,把回調經過實參傳遞

var tAjax = function(config) {
    var url      = config.url;
    var complete = config.complete; 
    var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
    xhr.open('post', url);
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4) {
            if (xhr.status == 200) {
                complete(xhr.responseText);
            }
        }
    }
    xhr.send();
}

這樣設計能夠看作相似工廠模式的封裝,好處不用多說,在工廠模式裏面包含了對象的建立等必要的邏輯,客戶端根據傳參選擇動態的實例化相對的處理

對於客戶端來去除了具體的依賴,固然tAjax你也能夠看做一個外觀模式提供的接口,其實就是隱藏了具體的複雜邏輯,提供一個簡單的接口,從而下降耦合

 


設計二:

tAjax({
    url: "php.html",
    complete: function(data) {
        console.log(data)
    }
}).done(function(data){
    console.log(data)
})

在以前加入了一個done鏈式處理,固然這裏done,實際上是deferred的一個成功處理通知,若是以前沒有接觸,你們去了解一下關於deferred的概念

咱們知道jQuery實現了鏈式,實現的原理沒法就是返回自己對象的引用

var ajax = tAjax({
    url: "php.html",
    complete: function(data) {
        console.log(data)
    }
})

ajax.done(function(){
    
})

以上是分離的狀況下,若是要合併成一條鏈式處理,只要在上一個方法中返回this便可

因此咱們改改

var tAjax = function(config) {

    var doneFn;

    var url      = config.url;
    var complete = config.complete; 
    var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
    xhr.open('post', url);
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4) {
            if (xhr.status == 200) {
                doneFn(xhr.responseText);
                complete(xhr.responseText);
            }
        }
    }

    xhr.send(xhr.responseText);

    return {
        /**
         * 返回一個done對象
         */
        done: function(ourfn) {
             doneFn = ourfn;
        }
    };
}

咱們返回了一個done對象,這裏同樣要是對象,由於鏈式的緣由,咱們看外部指定了內部的done,從而把外部函數給引用到內部的doneFn上 緩存起來

xhr.staturs 成功後一塊兒執行

固然這種設計是有問題的,若是在done以後我在鏈式就確定不行,由於對象的引用錯了,那麼jQuery是如何處理?

 


設計三

提供document對象的全局處理

$(document).ajaxComplete(function() {
    console.log('ajax請求成功')
});


tAjax({
    url: "php.html",
    complete: function(data) {
         console.log(data)
    }
}).done(function(data){
    console.log(data)
})

這裏的問題就是把ajax內部的事件,返回給全局捕獲了,有點相似css3的全局動畫事件

這裏的設計其實最簡單了由於自己之間沒有什麼耦合,就是發送一個事件給document便可

jQuery利用了trigger自定義事件觸發的

globalEventContext.trigger("ajaxComplete", [jqXHR, s]);

具體每一種實如今後面的都會提到,在這裏須要你們有個總體的印象,

 


總結:

經過讀閱jQuery.ajax這段api咱們能夠看到jQuery對ajax的處理作的至關的全面

首先咱們常常遇到某些耗時很長的javascript操做。其中,既有異步的操做(好比ajax讀取服務器數據),也有同步的操做(好比遍歷一個大型數組),它們都不是當即能獲得結果的。

一般的作法是,爲它們指定回調函數(callback)。即事先規定,一旦它們運行結束,應該調用哪些函數。

ajax引入了deferred方案,callback方案就是回調函數解決方案,從而處理耗時操做的問題,對那些操做提供了更好的控制,以及統一的編程接口

伴隨Ajax請求會觸發若干事件,咱們能夠訂閱這些事件並在其中處理咱們的邏輯。

在jQuery中有兩種Ajax事件:局部事件和全局事件。

局部事件(回調函數),在$.ajax()方法的options參數中聲明,能夠用來設置請求數據和獲取、處理響應數據。

全局事件,每次Ajax請求都會觸發,它會向DOM中的全部元素廣播,你只需爲DOM中任意元素bind好全局事件即會觸發(若綁定屢次,則會依次觸發爲事件註冊的回調函數

除此以外,還提供了一系列的簡化接口,好比.load ,還有直接對數據對象序列化的能力,對跨域的處理,contentType的修復等等

深刻待續。。。。。

相關文章
相關標籤/搜索