jQuery 源碼解析代碼及更多學習乾貨: 猛戳GitHub前端
本篇代碼爲 my-jQuery 1.0.4.jsgit
建議閱讀本篇先弄懂上一篇Callbacks 原理分析,由於Deferred異步回調是基於Callbacks。下載源碼而後根據文章思路學習,最好本身邊思考邊多敲幾遍。es6
首先推薦各位閱讀一下 Promise/A+規範github
Promise做爲一個模型,提供了一個在軟件工程中描述的延時概念的解決方案。ajax
Promise是ES6提出的異步編程模式,能夠參考阮一峯ES6- Promise編程
Deferred是jQuery提出的回調函數解決方案,主要依賴Callbacks回調,能夠參考上一篇Callbacks原理解析。設計模式
主要解決的問題是:當一個異步依賴於另外一個異步請求的結果時,或者某個操做須要等另外幾個操做都結束後纔開始等,更強大的是從ajax操做擴展到了全部操做,動畫、定時中也經常使用。數組
(1) $.Deferred()
生成一個deferred對象。promise
(2)deferred.done()
指定操做成功時的回調函數bash
(3) deferred.fail()
指定操做失敗時的回調函數
(4) .promise()
返回一個Promise對象來觀察當某種類型的全部行動綁定到結合,排隊與否仍是已經完成。
(5) deferred.resolve()
手動改變deferred對象的運行狀態爲"已完成",從而當即觸發done()
方法。
(6)deferred.reject()
這個方法與deferred.resolve()
正好相反,調用後將deferred對象的運行狀態變爲"已失敗",從而當即觸發fail()
方法。
(7) $.when()
爲多個操做指定回調函數。 除了這些方法之外,deferred對象還有二個重要方法,上面的教程中沒有涉及到。
(8)deferred.then()
有時爲了省事,能夠把done()
和fail()
合在一塊兒寫,這就是then()
方法。
(9)deferred.progress()
當Deferred(延遲)對象生成時,調用已添加的處理程序。
// jQuery Deferred 寫法
var dtd = $.Deferred();// 新建一個Deferred對象
var wait = function(dtd){
var tasks = function(){
alert("執行完畢");
dtd.resolve();//改變Deferred對象的執行狀態 成功狀態
};
setTimeout(tasks,2000);
return dtd;
};
// 延遲對象的狀態 決定調用哪一個隊列的處理函數
$.when(wait(dtd))
.done(function(){
alert("成功啦");
}).fail(function(){
alert("出錯了");
})
// dtd.resolve(); 改變dtd的執行狀態致使done馬上執行
// dtd.reject(); 改變dtd的執行狀態致使fail馬上執行
// dtd.resolve();
複製代碼
以上代碼輸出:
執行完畢
成功啦
經過以上代碼,咱們反推jQuery的源碼是如何實現的。
3.源碼的設計思路:
如下僅爲核心代碼片斷,完整代碼請點擊源碼分析下載
(1)首先定義了tuples的數據結構,用來組裝存儲異步延遲三種不一樣狀態信息的描述.
/**
* tuples 定義一個數組來存儲三種不一樣狀態信息的描述
* 第一個參數 延時對象的狀態
* 第二個參數 往隊列裏添加處理函數
* 第三個參數 建立不一樣狀態的隊列
* 第四個參數 記錄最終狀態信息
* **/
var tuples = [
["resolve","done",jQuery.Callbacks("once memory"),"resolved"],
["reject","fail",jQuery.Callbacks("once memory"),"rejected"],
["notify","progress",jQuery.Callbacks("memory")]]
複製代碼
(2)而後定義一個promise
用來封裝state,then,promise
對象
promise = {
state :function(){
return state;
},
then:function() {
},
promise:function(obj) {
console.log(promise);
debugger
return obj !=null ? jQuery.extend(obj,promise):promise;
}
},
複製代碼
(3)定義一個延遲對象 deferred = {};
(4)遍歷封裝好的tuples數組隊列,把數組裏第二個元素也就是映射到Callbacks而且給到list,將數組裏第三個元素記錄最終狀態的信息給到stateString,而後把數組第一個元素即延時對象的狀態映射到Callbacks的add方法上,定義輔助方法deferred[resolveWith]
,deferred[rejectWith]
,deferred[notifyWith]
,最後調用Callbacks的fireWith方法實現隊列的回調。
// 遍歷 tuples
tuples.forEach(function(tuple,i){
var list = tuple[2], // 建立隊列 建立三次 self對象的引用 映射 調用Callbacks裏面的方法
stateString = tuple[3]; // 拿到當前最終信息的描述
// promise[done | fail |progress] 將這三個狀態都拿到Callbacks self裏面方法的引用 添加處理函數
promise[tuple[1]] = list.add;
// Handle state 成功或者失敗
if (stateString) { //添加第一個處理程序
list.add(function(){
// state = [resolved | rejected]
state = stateString;
});
}
// deferred [resolve | reject | notify ] 延時對象的狀態拿到函數的引用
deferred[tuple[0]] = function(){
deferred[tuple[0] + "With"] (this === deferred ? promise : this, arguments);
return this;
};
// list.fireWith 執行隊列而且傳參
// 調用隊列中的處理函數 而且給他們傳參 綁定執行時的上下文對象
deferred[tuple[0] + "With"] = list.fireWith;
});
複製代碼
(5)將deferred返回出去
// Make the deferred a promise
promise.promise(deferred);
return deferred;
複製代碼
(6)定義一個when方法
// 執行一個或多個對象的延遲函數的回調函數
when : function(subordinate){
return subordinate.promise();
}
});
複製代碼
至此,大功告成,實現了jQuery的源碼剖析,體會了到做者的數據結構隊列處理編程思想
Deferred設計圖:
jQuery 源碼剖析 系列目錄地址:猛戳GitHub
jQuery 源碼剖析 系列預計寫十篇左右,旨在加深對原生JavaScript 部分知識點的理解和深刻,重點講解 jQuery核心功能函數、選擇器、Callback 原理、延時對象原理、事件綁定、jQuery體系結構、委託設計模式、dom操做、動畫隊列等。 若是有錯誤或者不嚴謹的地方,請務必給予指正,十分感謝。若是喜歡或者有所啓發,歡迎 star⭐️,對做者也是一種鼓勵。
關注公衆號回覆:學習 領取前端最新最全學習資料,也能夠進羣和大佬一塊兒學習交流