jQuery deferred应用dom加载完毕详细源码分析(三)
? 我承認上章ajax部分寫得不好,不要怪我,它的ajax代碼太多了,而且跨越大,方法跳躍多,實在不好排版與講解,但如果你真正想研究源碼并且仔細讀了得話,你的
收獲應該會很大,至少你明白了js的ajax是怎么回事.不懂得可以繼續參閱ajax和Deferred ,其實我更希望你把deferred搞懂了在看這部分.
? 好吧,言歸正傳,這次我講得是$(function(){console.log("dom ready")}); 多么簡單的一段代碼,但它是在每個瀏覽器運行的呢?
? 還是先來個全局展望,會用到以下幾個方法,這里你會知道jQuery是真正的hold住哥,因為他要hold dom ready event holdReady,一個神奇的方法
? $(fn)?? -->? $.fn.ready(fn)? -->$.bindReady()? --> ? ?? $.ready(wait)???? <--> $.holdReady(hold)
?下面這個是init函數的一部分代碼,就是判斷$里面的參數是函數
1 // 處理: $(function) 簡寫 $(document).ready(function)2 if (jQuery.isFunction(selector)) {
3 return rootjQuery.ready(selector); ->所以這里你應該明白了為什么可以$(fn) 替代$(document).ready(fn)
4 } --> rootjQuery=$(document)
那$(document).ready(fn)后又怎么辦呢? 難道$(document)不是實例化的一個jQuery對象,它當然又要去調用$.fn.ready的函數
?好,來到了$.fn.ready,好吧這個函數并沒有管如何處罰dom ready事件,而只是關心callbacks函數隊列fn ,意思就是你$(fn1),$(fn2),
它靠得還是全局的readyList,然后這個readyList是一個Deferred對象,知道它的重要了吧!
1 /*$(fn)--> $(document).ready(fn) 為什么是$(document)而不是其他$("body")呢?2 * $(function () {console.log(this === document); }); -->true
3 */
4 ready: function (fn) {
5 // Attach the listeners
6 jQuery.bindReady();
7
8 //增加$(fn)里的回調函數 以便domready觸發時候 readyList.resolveWith(document,[jQuery]); 這里readyList是全局的變量
9 readyList.done(fn);
10
11 return this;
12 },
--->這里可以看到,繼續去調用$.bindReady(),這里不關系dom ready是如何觸發的
來到bindReady函數,根據不同的函數支持情況進行了不同的處理,在這里多少能學點瀏覽器兼容的知識了吧,
其實學了jQuery,神馬瀏覽器兼容知識你都學到了.但是這個函數真正關心得只是事件的添加,不關心事件如何觸發,,
這里最終的callback觸發還是交給了$.ready? 這里會有一個DOMContentLoaded公用的函數
1 /* 從這里可以看出來其實$(function(){})如果頁面存在很多的話,也不太會影響性能,因為這個$.bindReady只執行一次2 * 而以后$(fn)進來的函數,都通過deferred的done函數添加進來,只要這個對象resolve了,立馬后面所有的fn立即執行
3 */
4 bindReady: function () {
5 //如果readyList存在,直接返回,證明這里已經創建了一個deferred對象
6 if (readyList) {
7 return;
8 }
9 //創建jQuery 私有的deferred
10 readyList = jQuery._Deferred();
11
12 //確保browser event已經觸發過后,$(document).ready()也將會被調用
13 //這個狀態表示Fully loaded,document已經完全加載了
14 if (document.readyState === "complete") {
-->jQuery代碼總擔心出錯,但是你不要擔心你的回調會因為多處的被添加到事件添加器中去而被多次觸發
--> $.ready會幫你處理的 ~_~
15 // Handle it asynchronously to allow scripts the opportunity to delay ready
16 return setTimeout(jQuery.ready, 1);
17 }
18
19 // Mozilla, Opera and webkit nightlies currently support this event
20 if (document.addEventListener) {
21 //支持DOMContentLoaded事件了,這樣就簡單了
22 document.addEventListener("DOMContentLoaded", DOMContentLoaded, false);
23
24 // A fallback to window.onload, that will always work ->jQuery代碼總擔心出錯,
//但是你不要擔心,這樣會不會多次觸發你的回調函數,告訴你當然不會!
25 window.addEventListener("load", jQuery.ready, false);
26
27 // If IE event model is used
28 } else if (document.attachEvent) {
29 //這里主要擔心頁面內有iframe,所以使用onreadystatechange觸發
30 document.attachEvent("onreadystatechange", DOMContentLoaded);
31
32 // A fallback to window.onload, that will always work
33 window.attachEvent("onload", jQuery.ready);
34
35 //如果是ie并且頁面window是toplevel的,繼續檢查 -> ie關心的代碼,doScrollCheck()又是神馬呢?
36 //MDN: window.frameElement == null if the window is top-level
37 var toplevel = false;
38
39 try {
40 toplevel = window.frameElement == null;
41 } catch (e) { }
42
43 if (document.documentElement.doScroll && toplevel) {
44 doScrollCheck();
45 }
46 }
47 },
//原來DOMContentLoaded還是在這里,最后都是交給了$.ready()處理,而DOMContentLoaded并沒有做什么,只是又一次的去掉事件監聽
?if (document.addEventListener) {
??????????? DOMContentLoaded = function () {
??????????????? document.removeEventListener("DOMContentLoaded", DOMContentLoaded, false);
??????????????? jQuery.ready();
??????????? };
??????? } else if (document.attachEvent) {
??????????? DOMContentLoaded = function () {
??????????????? // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
??????????????? if (document.readyState === "complete") {
??????????????????? document.detachEvent("onreadystatechange", DOMContentLoaded);
??????????????????? jQuery.ready();
??????????????? }
??????????? };
??????? }
?/* 這里只針對ie,當頁面DOM未加載完成時,調用doScroll方法時,會產生異常。
? * 那么我們反過來用,如果不異常,那么就是頁面DOM加載完畢了!
? * 這里的想法真的很淫蕩!
? */
??????? function doScrollCheck() {
??????????? if (jQuery.isReady) {
??????????????? return;
??????????? }
??????????? try {
??????????????? // If IE is used, use the trick by Diego Perini
??????????????? // http://javascript.nwbox.com/IEContentLoaded/
??????????????? document.documentElement.doScroll("left");
??????????? } catch (e) {
??????????????? setTimeout(doScrollCheck, 1);
??????????????? return;
??????????? }
??????????? //直到沒有異常的時候,執行$.ready()
??????????? jQuery.ready();
??????? }
-->你最終會發現,其實都是交給了$.ready()處理,不管你怎么觸發事件 ^_^
?好吧,最后所有的重頭戲都落到了ready,最后的callbacks都是靠他觸發的,而他里面的readyList又一是一個deferred對象,你懂了吧,他要
resolveWith(document,[jQuery]),你知道這個document意味著什么嗎?$(function(){console.log(this===document)}) ~_~.
1 /* $.holdReady 原來jQuery才是真正的hold住哥,這里它要hold domReady事件,2 * $.holdReady(true)--> 延遲hold一次,延遲domReady事件觸發
3 * $.holdReady(false) --> 釋放hold一次,如果釋放后$.readyWait=0,則觸發domReady事件
4 * 整個函數的功能就是延遲domReady事件,比如你需要動態加載一個jQuery插件神馬的,然后你又要使用這個插件
5 * $.holdReady(true);$.getScript("myplugin.js", function() { $.holdReady(false);});
6 ->使用上面這個語句整個場面都hold住了,加載完成后釋放
7 */
8 holdReady: function (hold) { -->這里你總算看到了神馬是hold住哥
9 if (hold) {
10 jQuery.readyWait++;
11 } else {
12 jQuery.ready(true);
13 }
14 },
15 /*歸根揭底,dom樹加載完成都是靠它來觸發callbacks,只是不同的瀏覽器通過不同的方式來觸發$.ready()
16 */
17 ready: function (wait) {
18 // 釋放hold狀態或者dom 事件觸發
19 if ((wait === true && ! --jQuery.readyWait) || (wait !== true && !jQuery.isReady)) {
20 // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
21 if (!document.body) {
22 return setTimeout(jQuery.ready, 1);
23 }
24
25 // 表面dom樹已加載完畢
26 jQuery.isReady = true;
27
28 //if 一個正常的dom函數事件觸發了,但是還有hold的狀態,返回把,先不觸發
29 if (wait !== true && --jQuery.readyWait > 0) {
30 return;
31 }
32 //觸發綁定在 readyList.done(fn);中得函數
33 //函數原來還是在這里觸發的
34 readyList.resolveWith(document, [jQuery]);
35
36 //觸發任何綁在document ready的事件
37 // $(document).bind({"ready": function () {alert("document ready");} });
38 if (jQuery.fn.trigger) {
39 jQuery(document).trigger("ready").unbind("ready");
40 }
41 }
42 },
?這上面有個2B的代碼 $(document).bind("ready",function(){..})不知道哪個2B青年會用這個方法...
好吧,如果看懂了上面的代碼,你完全可以寫一個自己的$(function(){}) 而不必為了jQuery為了符合大眾的口味去這樣實現!
轉載于:https://www.cnblogs.com/nothingbrother/archive/2011/12/05/2277369.html
總結
以上是生活随笔為你收集整理的jQuery deferred应用dom加载完毕详细源码分析(三)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 项目管理其实可以简单一点——任务分工
- 下一篇: StringBuffer