DOMContentLoaded 與onload區(qū)別以及使用

一涕蚤、何時觸發(fā)這兩個事件宪卿?

1的诵、當 onload 事件觸發(fā)時,頁面上所有的DOM愧捕,樣式表奢驯,腳本,圖片次绘,flash都已經(jīng)加載完成了瘪阁。

2、當 DOMContentLoaded 事件觸發(fā)時邮偎,僅當DOM加載完成管跺,不包括樣式表,圖片禾进,flash豁跑。

二、為什么要區(qū)分泻云?

開發(fā)中我們經(jīng)常需要給一些元素的事件綁定處理函數(shù)艇拍。但問題是,如果那個元素還沒有加載到頁面上宠纯,但是綁定事件已經(jīng)執(zhí)行完了卸夕,是沒有效果的。這兩個事件大致就是用來避免這樣一種情況婆瓜,將綁定的函數(shù)放在這兩個事件的回調(diào)中快集,保證能在頁面的某些元素加載完畢之后再綁定事件的函數(shù)。

當然DOMContentLoaded機制更加合理廉白,因為我們可以容忍圖片个初,flash延遲加載,卻不可以容忍看見內(nèi)容后頁面不可交互猴蹂。

這里又要牽扯到頁面加載渲染的原理了:

1院溺、加載樣式表會阻塞外鏈腳本的執(zhí)行

一些Gecko和Webkit引擎版本的瀏覽器,包括IE8在內(nèi)磅轻,會同時發(fā)起多個Http請求來并行下在樣式表和腳本珍逸。但腳本不會被執(zhí)行,直到樣式被加載完成瓢省。在未加載完之前甚至頁面也不會被渲染弄息。但是在opera中樣式的加載不會阻塞腳本的執(zhí)行。

因此:目前通用的作法是把腳本和樣式都以外鏈形式引入勤婚,甚至在jquery的官方文檔中也是這樣推薦的摹量。對于大部分腳本來說,這樣的腳本等待外鏈的機制還是有意義的,比如一些DOM和樣式操作需要讀取元素的位置缨称,顏色等凝果。這就需要樣式先于腳本加載

檢驗方法:嘗試強制使服務器端使style延遲一段時間才加載(甚至10秒),測試的結果是睦尽,在某些版本的Firefox器净,Chrome中最后一段腳本仍然是可以讀出style的屬性值(因為style始終先于javascript加載),比如#FF0000或者rgb(255, 0, 0)当凡,而這驗證了我上面的說法山害。而在opera中卻無法讀出style的屬性。代碼如下:

html 文件內(nèi)容
<!DOCTYPE html>
<head>
    <linkrel="stylesheet"href="stylesheet.css">
    <scriptsrc="script.js"></script>
</head>
<body>
    <divid="element">The element</div><
/body>
</html>


stylesheet.css 文件內(nèi)容
#element { color: red; }


script.js文件內(nèi)容
document.addEventListener('DOMContentLoaded',function(){
     alert(getComputedStyle(document.getElementById('element'),null).color);},
false);

2沿量、各大javascript框架如何實現(xiàn)domReady事件的

早期版本的瀏覽器是沒有DOMContentLoaded事件的那么它們怎么模擬實現(xiàn)類似功能呢浪慌?先來說說原理

(1)、如果是webkit引擎則輪詢document的readyState屬性朴则,當值為loaded或者complete時則觸發(fā)DOMContentLoaded事件权纤,對webkit525之后版本直接可以注冊DOMContentLoaded事件

if(Browser.Engine.webkit){  
    timer = window.setInterval(function(){
  if(/loaded|complete/.test(document.readyState))  
      fireContentLoadedEvent();
  },0);
}

(2)、IE處理方式有多種

a乌妒、在頁面臨時插入一個script元素汹想,并設置defer屬性,最后把該腳本加載完成視作DOMContentLoaded事件來觸發(fā)撤蚊。這樣做有一個問題是古掏,如果插入腳本的頁面包含iframe的話,會等到iframe加載完才觸發(fā)拴魄,其實這與onload是無異的冗茸。即這個方法不準確席镀。

b匹中、通過setTiemout來不斷的調(diào)用documentElement的doScroll方法,直到調(diào)用成功則出觸發(fā)DOMContentLoaded豪诲。這樣做的原理是在IE下顶捷,DOM的某些方法只有在DOM解析完成后才可以調(diào)用,doScroll就是這樣一個方法屎篱,反過來當能調(diào)用doScroll的時候即是DOM解析完成之時服赎,與prototype中的document.write相比,該方案可以解決頁面有iframe時失效的問題

c交播、首先注冊document的onreadystatechange事件重虑,但經(jīng)測試后該方法與window.onload相當,效果不大秦士。下面是jquery做的兼容性處理代碼缺厉。

document.attachEvent("onreadystatechange",
  function(){
    if( document.readyState ==="complete"){  
          document.detachEvent("onreadystatechange", arguments.callee );  
        jQuery.ready();}
});

接下來具體看一看幾大前端框架是如何綜合運用這幾個方法的。

jQuery.ready.promise = function( obj ) {//定義一個狀態(tài)機
    if ( !readyList ) {//保證頁面只創(chuàng)建一個延遲對象,多次使用$.ready() 則直接使用延遲對象done方法加入回調(diào)隊列
 
        readyList = jQuery.Deferred();//異步延遲對象
        // readyRE = /complete|loaded|interactive/,
        // Catch cases where $(document).ready() is called after the browser event has already occurred.
        // we once tried to use readyState "interactive" here, but it caused issues like the one
        // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
        if ( document.readyState === "complete" ) {//
          這個屬性是只讀的提针,傳回值有以下的可能:
          //0-UNINITIALIZED:XML 對象被產(chǎn)生命爬,但沒有任何文件被加載。 
          //1-LOADING:加載程序進行中辐脖,但文件尚未開始解析饲宛。 
          //2-LOADED:部分的文件已經(jīng)加載且進行解析,但對象模型尚未生效嗜价。 
          //3-INTERACTIVE:僅對已加載的部分文件有效艇抠,在此情況下,對象模型是有效但只讀的久锥。 
          //4-COMPLETED:文件已完全加載练链,代表加載成功
// Handle it asynchronously to allow scripts the opportunity to delay ready
            setTimeout( jQuery.ready );
 
        // Standards-based browsers support DOMContentLoaded
        } else if ( document.addEventListener ) {//符合W3C標準的瀏覽器
            // Use the handy event callback
            document.addEventListener( "DOMContentLoaded", completed, false );
 
            // A fallback to window.onload, that will always work
            window.addEventListener( "load", completed, false );//還是給load事件注冊了事件,以防不測奴拦,做為回滾用
 
        // If IE event model is used
        } else {
            // Ensure firing before onload, maybe late but safe also for iframes
            document.attachEvent( "onreadystatechange", completed );
 
            // A fallback to window.onload, that will always work
            window.attachEvent( "onload", completed );
 
            // If IE and not a frame
            // continually check to see if the document is ready
            var top = false;
 
            try {//判斷是否為iframe媒鼓,如果不是的話采用不斷的輪詢scorll的方法
                top = window.frameElement == null && document.documentElement;
            } catch(e) {}
 
            if ( top && top.doScroll ) {
                (function doScrollCheck() {
                    if ( !jQuery.isReady ) {
 
                        try {
                            // Use the trick by Diego Perini
                            // http://javascript.nwbox.com/IEContentLoaded/
                            top.doScroll("left");
                        } catch(e) {
                            return setTimeout( doScrollCheck, 50 );
                        }
 
                        // detach all dom ready events
                        detach();
 
                        // and execute any waiting functions
                        jQuery.ready();//實際:readyList.resolveWith( document, [ jQuery ] );
                    }
                })();
            }
        }
    }
    return readyList.promise( obj );
};

再貼上幾段其他框架的代碼,大同小異错妖,就不具體分析了

prototype

(function(GLOBAL) {
  /* Support for the DOMContentLoaded event is based on work by Dan Webb,
     Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */
  
  var TIMER;
  
  function fireContentLoadedEvent() {
    if (document.loaded) return;
    if (TIMER) window.clearTimeout(TIMER);
    document.loaded = true;
    document.fire('dom:loaded');
  }
  
  function checkReadyState() {
    if (document.readyState === 'complete') {
      document.detachEvent('onreadystatechange', checkReadyState);
      fireContentLoadedEvent();
    }
  }
  
  function pollDoScroll() {
    try {
      document.documentElement.doScroll('left');
    } catch (e) {
      TIMER = pollDoScroll.defer();
      return;
    }
    
    fireContentLoadedEvent();
  }


  if (document.readyState === 'complete') {
    // We must have been loaded asynchronously, because the DOMContentLoaded
    // event has already fired. We can just fire `dom:loaded` and be done
    // with it.
    fireContentLoadedEvent();
    return;
  }
  
  if (document.addEventListener) {
    // All browsers that support DOM L2 Events support DOMContentLoaded,
    // including IE 9.
    document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
  } else {
    document.attachEvent('onreadystatechange', checkReadyState);
    if (window == top) TIMER = pollDoScroll.defer();
  }
  
  // Worst-case fallback.
  Event.observe(window, 'load', fireContentLoadedEvent);
})(this);

mootools

(function(GLOBAL) {
  /* Support for the DOMContentLoaded event is based on work by Dan Webb,
     Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */
  
  var TIMER;
  
  function fireContentLoadedEvent() {
    if (document.loaded) return;
    if (TIMER) window.clearTimeout(TIMER);
    document.loaded = true;
    document.fire('dom:loaded');
  }
  
  function checkReadyState() {
    if (document.readyState === 'complete') {
      document.detachEvent('onreadystatechange', checkReadyState);
      fireContentLoadedEvent();
    }
  }
  
  function pollDoScroll() {
    try {
      document.documentElement.doScroll('left');
    } catch (e) {
      TIMER = pollDoScroll.defer();
      return;
    }
    
    fireContentLoadedEvent();
  }


  if (document.readyState === 'complete') {
    // We must have been loaded asynchronously, because the DOMContentLoaded
    // event has already fired. We can just fire `dom:loaded` and be done
    // with it.
    fireContentLoadedEvent();
    return;
  }
  
  if (document.addEventListener) {
    // All browsers that support DOM L2 Events support DOMContentLoaded,
    // including IE 9.
    document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
  } else {
    document.attachEvent('onreadystatechange', checkReadyState);
    if (window == top) TIMER = pollDoScroll.defer();
  }
  
  // Worst-case fallback.
  Event.observe(window, 'load', fireContentLoadedEvent);
})(this);

紙上學來終覺淺绿鸣,絕知此事要躬行。自己寫一段暂氯。

(function(window,undefined){
    hobo = {}
    var readyList = [],
    _isReady =false;

    function readyFn(){
        console.log(event.type)
        if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
            detach();

             _isReady =true;

            fireReady();
        
   
         }
    }
    
  function fireReady(){
      for (var i = 0,fn; fn = readyList[i++];) {
                fn();
          };
      readyList = null;

      fireReady = function(){}//惰性函數(shù)潮模,防止IE9二次調(diào)用
  }


    function detach() {
        if ( document.addEventListener ) {
            
            document.removeEventListener( "DOMContentLoaded", readyFn, false );
            window.removeEventListener( "load", readyFn, false );

        } else {
            document.detachEvent( "onreadystatechange", readyFn );
            window.detachEvent( "onload", readyFn );
        }
    }


    hobo.ready = function(fn){
         if(readyList){
            readyList.push(fn)
         }

         if(readyList.length>1){
            return;
         }   

         if(document.readyState === 'complete'){
            setTimeout(readyFn);
         }else if (document.addEventListener) {//符合W3C 則監(jiān)聽 DOMContentLoaded和load事件
                 console.log('addEventListener')
                document.addEventListener('DOMContentLoaded',readyFn,false);
                document.addEventListener('DOMContentLoaded',readyFn,false);
         }else{//針對IE
                console.log('attachEvent')
            document.attachEvent('onreadystatechange',readyFn);

            document.attachEvent('onload',readyFn);
         }

            //針對IE并且非frame
            var top = false;
            try{
                top = window.frameElement===null&&document.documentElement
            }catch(e){}

            if(top&&top.doScroll){
                (function doScrollCheck(){
                    if (!_isReady) {
                         try {//每隔50秒輪詢 檢測是否支持doScroll()方法
                            top.doScroll("left");
                        } catch(e) {
                            return setTimeout( doScrollCheck, 50 );
                        }
                    };
                })
            }

    }
    window.hobo =hobo
}(window,void 0))


//使用

hobo.ready(function(){
    console.log(11111);
})
hobo.ready(function(){
    console.log(22222);
})
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市痴施,隨后出現(xiàn)的幾起案子擎厢,更是在濱河造成了極大的恐慌,老刑警劉巖辣吃,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件动遭,死亡現(xiàn)場離奇詭異,居然都是意外死亡神得,警方通過查閱死者的電腦和手機厘惦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來哩簿,“玉大人宵蕉,你說我怎么就攤上這事〗诎瘢” “怎么了羡玛?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長宗苍。 經(jīng)常有香客問我稼稿,道長亿遂,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任渺杉,我火速辦了婚禮蛇数,結果婚禮上,老公的妹妹穿的比我還像新娘是越。我一直安慰自己耳舅,他們只是感情好,可當我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布倚评。 她就那樣靜靜地躺著浦徊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪天梧。 梳的紋絲不亂的頭發(fā)上盔性,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天,我揣著相機與錄音呢岗,去河邊找鬼冕香。 笑死,一個胖子當著我的面吹牛后豫,可吹牛的內(nèi)容都是我干的悉尾。 我是一名探鬼主播,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼挫酿,長吁一口氣:“原來是場噩夢啊……” “哼构眯!你這毒婦竟也來了?” 一聲冷哼從身側響起早龟,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤惫霸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后葱弟,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體壹店,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年翘悉,在試婚紗的時候發(fā)現(xiàn)自己被綠了茫打。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片居触。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡妖混,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出轮洋,到底是詐尸還是另有隱情制市,我是刑警寧澤,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布弊予,位于F島的核電站祥楣,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜误褪,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一责鳍、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧兽间,春花似錦历葛、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至帜羊,卻和暖如春咒程,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背讼育。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工帐姻, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人奶段。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓卖宠,卻偏偏與公主長得像,于是被迫代替她去往敵國和親忧饭。 傳聞我的和親對象是個殘疾皇子扛伍,可洞房花燭夜當晚...
    茶點故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 1.幾種基本數(shù)據(jù)類型?復雜數(shù)據(jù)類型?值類型和引用數(shù)據(jù)類型?堆棧數(shù)據(jù)結構? 基本數(shù)據(jù)類型:Undefined、Nul...
    極樂君閱讀 5,502評論 0 106
  • 1.幾種基本數(shù)據(jù)類型?復雜數(shù)據(jù)類型?值類型和引用數(shù)據(jù)類型?堆棧數(shù)據(jù)結構? 基本數(shù)據(jù)類型:Undefined词裤、Nul...
    伯納烏的追風少年閱讀 25,801評論 2 46
  • 最近兩期曉松講到了日本料理界的工匠精神 從米其林一星到三星刺洒,一份菜單三十年不變,只追求對味道的領悟 在這種人人只顧...
    Betteremma閱讀 190評論 0 0
  • 輕啜一杯潤枯腸 怎奈人走茶就涼 富貴如若有根在 豈不遍地秦始皇 寒門之子須努力 白屋佳兒讀書忙 他朝一躍騰空起 不...
    一葉茶閱讀 197評論 1 3
  • 情緒-刺激源(真實的應激反應):破碎 心理素質(zhì)(應對策略):熟知 #新發(fā)表的論文# 【閱讀文獻吼砂、設計實驗逆航、數(shù)據(jù)統(tǒng)計...
    珍珍Pearl閱讀 158評論 0 0