1. 程式人生 > >DOMContentLoaded時間觸發與js,css,img的關聯

DOMContentLoaded時間觸發與js,css,img的關聯

DOMContentLoaded觸發原理:

1、規範總是那麼的晦澀,但至少有一點是可以明確了的,就是在JS(不包括動態插入的JS)執行完之後,才會觸發DOMContentLoaded事件。

2、DOMContentLoaded事件本身不會等待CSS檔案、圖片、iframe載入完成。
它的觸發時機是:載入完頁面,解析完所有標籤(不包括執行CSS和JS),並如規範中所說的設定interactive 和執行每個靜態的script標籤中的JS,然後觸發。
而JS的執行,需要等待位於它前面的CSS載入(如果是外聯的話)、執行完成,因為JS可能會依賴位於它前面的CSS計算出來的樣式

實踐是檢驗真理的唯一標準

實踐是檢驗真理的唯一標準

實驗1:DOMContentLoaded事件不直接等待CSS檔案、圖片的載入完成

index.html:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title></title>
    <link rel="stylesheet" type="text/css" href="./css/main.css">
</head>
<body>
    <p>Content</p>
    <img src="./img/chrome-girl.jpg">
</body>
</html>


圖一

如果頁面中沒有script標籤,DOMContentLoaded事件並沒有等待CSS檔案、圖片載入完成。

Chrome開發者工具的Timeline面板可以幫我們記錄下瀏覽器的一舉一動。圖一中紅色小方框中的藍線,表示DOMContentLoaded事件,它右邊的紅線和綠線分別表示load事件和First paint,滑鼠hover在這些線露出灰色方框下面的一小部分時就會出現帶有說明文字的tips(這互動夠反人類的對吧!)。

實驗2:DOMContentLoaded事件需要等待JS執行完才觸發

index.html:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript">
        console.timeStamp('Inline script before link in head');
        window.addEventListener('DOMContentLoaded', function(){
            console.timeStamp('DOMContentLoaded event');
        });
    </script>
    <link rel="stylesheet" type="text/css" href="./css/main.css">
    <script type="text/javascript">
        console.timeStamp('Inline script after link in head');
    </script>
</head>
<body>
    <p>Content</p>
    <img src="./img/chrome-girl.jpg">
    <script type="text/javascript" src="./js/main.js"></script>
</body>
</html>

main.js:

console.timeStamp('External script after link in body');

圖二

如果頁面中靜態的寫有script標籤,DOMContentLoaded事件需要等待JS執行完才觸發。
而script標籤中的JS需要等待位於其前面的CSS的載入完成。

console.timeStamp() 可以向Timeline中新增一條記錄,並對應上方的一條黃線。

從圖二中可以看出,在CSS之前的JS立刻得到了執行,而在CSS之後的JS,需要等待CSS載入完後才執行,比較明顯的是main.js早就載入完了,但還是要等main.css載入完才能執行。而DOMContentLoaded事件,則是在JS執行完後才觸發。滑動Timeline面板中表示展示區域的滑塊,如圖三,放大後即可看到表示DOMContentLoaded事件的藍線(之前跟黃線和綠線靠的太近了),當然,通過 console.timeStamp()向TimeLine中新增的記錄也可證明其觸發時間。


圖三

現代瀏覽器會併發的預載入CSS, JS,也就是一開始就併發的請求這些資源,但是,執行CSS和JS的順序還是按原來的依賴順序(JS的執行要等待位於其前面的CSS和JS載入、執行完)。先載入完成的資源,如果其依賴還沒載入、執行完,就只能等著。

實驗3:img何時開始解碼、繪製?

從圖三中我們可以發現一個有趣的地方:img的請求老早就發出了,但延遲了一段時間才開始解碼。如圖二、圖三中的紅框所示,截圖中只框出了一部分表示解碼的記錄,而實際上這些表示解碼的記錄一直持續到img載入結束,如圖四所示,img是一邊載入一邊解碼的:


圖四

抱著“猜想——驗證”的想法,我猜想這是因為img這個資源是否需要展現出來,需要等 所有的JS和CSS的執行完 才知道,因為main.js可能會執行某些DOM操作,比如刪除這個img元素,或者修改其src屬性,而CSS可能會將其 display: none 。


圖五


圖六


圖七

圖五中沒有JS和CSS,img的資料一接收到就馬上開始解碼了。
圖六中沒有JS,但img要等到CSS載入完才開始解碼。
圖七的程式碼跟圖六的程式碼唯一的區別是CSS把img給 display: none; ,這使得img雖然請求了,但根本沒有進行解碼。
這說明,img是否需要解碼、繪圖(paint)出來,確實需要等CSS載入、執行完才能知道。也就是說,CSS會阻塞img的展現!那麼JS呢?


圖八

圖八對應的程式碼:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript">
        console.timeStamp('Inline script in head');
        window.addEventListener('DOMContentLoaded', function(){
            console.timeStamp('DOMContentLoaded event');
        });
    </script>
</head>
<body>
    <p>Content</p>
    <img src="./img/chrome-girl.jpg">
    <script type="text/javascript" src="./js/main.js"></script>
</body>
</html>

非常令人驚訝,在有JS而沒有CSS的頁面中,img居然能夠在收到資料後就立刻開始解碼、繪圖(paint),也就是說,JS並沒有阻塞img的展現!這跟我們以前理解的JS會阻塞img資源的傳統觀念不太一樣,看來Chrome對img的載入和展現做了新的優化。

我們常用的jQuery的 $(document).ready() 方法,就是對DOMContentLoaded事件的監聽(當然,其內部還會通過模擬DOMContentLoaded事件和監聽onload事件來提供降級方案)。通常推薦在DOMContentLoaded事件觸發的時候為DOM元素註冊事件。所以儘快的讓DOMContentLoaded事件觸發,就意味著能夠儘快讓頁面可互動:

  1. 減小CSS檔案體積,把單個CSS檔案分成幾個檔案以並行載入,減少CSS對JS的阻塞時間
  2. 次要的JS檔案,通過動態插入script標籤來載入(動態插入的script標籤不阻塞DOMContentLoaded事件的觸發)
  3. CSS中使用的精靈圖,可以利用對img的預載入,放在html中跟CSS檔案一起載入

在做實驗的過程中,感覺Chrome開發者工具的Timeline面板非常強大,瀏覽器的一舉一動都記錄下來。以前我們前端開發要想理解、探索瀏覽器的內部行為,或者摸著石頭過河的做黑盒測試,或者事倍功半的研究瀏覽器原始碼,唯一高效點的做法就是學習別人的研究經驗,看老外的文章,但瀏覽器的發展日新月異(比如這次實驗發現的JS不阻塞img的展現),別人的經驗始終不是最新、最適合的,關鍵是要結合自己的業務、需求場景,有針對性的做分析和優化。

相關推薦

DOMContentLoaded時間觸發jscssimg關聯

DOMContentLoaded觸發原理: 1、規範總是那麼的晦澀,但至少有一點是可以明確了的,就是在JS(不包括動態插入的JS)執行完之後,才會觸發DOMContentLoaded事件。 2、DOMContentLoaded事件本身不會等待CSS檔案、圖片、ifra

maven jetty 啟動後不能修改靜態文件jscsshtml

9.4 拷貝 ram 啟動 maven pom jar包 conf text 解決辦法: 1.從jetty的jar包中(位置可能不同,有的jetty-web中)拷貝一份webdefault.xml文件 2.將webdefault.xml 中的useFileMappedBuf

web.xml中的dispatchservlet後jscss甚至gif都不能正常顯示

startup view details article 的人 核心 默認 href com 這個可以說是很多初學Springmvc的人都會碰到一個令人頭痛的問題 那就是為什麽我配置好web.xml中的dispatchservlet後,js,css,甚至gif都不能正常顯示

iOS 加載本地HTMLcssjs

fill 簡書 p標簽 一道 bundle www string text orien 在IOS開發中,可以通過webView來加載HTML文件 步驟如下: 1.需要有一個webView,可以通過storyboard拖拽一個 或者 alloc 一個(我在這裏是拖拽了一個

前端過濾htmlcssjs

<div class="container-fluid"><!-- container-fluid --> <div class="row">        <div class="col-md-9">

JQuery使用load方法載入外部div時cssjs無效的辦法

問題: 一個html頁面a.html的js指令碼中,用$(‘selector’).load方法,載入另一個html頁面b.html中內容,b.html中css、js都失效。 解決辦法一: 第一步:在a.html的js指令碼中,使用load載入全部b.html,這樣b

python學習之網站的編寫(HTMLCSSJS)(十七)----------示例構造一個網頁的框架上部標題登入logo左側選單右側內容原始碼

結果: 顏色為了明顯,所以較為難看,可以根據自己的需要進行更改 原始碼: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title

python學習之網站的編寫(HTMLCSSJS)(十六)----------示例構造一個左側管理選單的功能點選主選單才顯示下面的內容

結果: 程式碼: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>逆水行舟不進則退</title>

python學習之網站的編寫(HTMLCSSJS)(十五)----------示例彈出一個背景為半黑色前面是白框的彈窗功能(已經編好的框架)

效果圖,程式碼直接可應用,按自己的需要在其中加入想要的內容:  程式碼及講解: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <

python學習之網站的編寫(HTMLCSSJS)(十四)----------CSS的display行內標籤和塊級標籤的轉換控制標籤是否顯示

行內標籤:有多大就佔多大,無法設定高度,寬度和邊距。 塊級標籤:佔一行,可以設定高度,寬度和邊距。 塊級標籤轉為行內標籤:display:inline 行內標籤轉為塊級標籤:display:block 還有一個特殊的轉換,既包含塊級標籤的屬性,又具有行內標籤的屬性,自己有多少佔多少,

python學習之網站的編寫(HTMLCSSJS)(十三)----------CSS字型和對齊方式的設定

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>逆水行舟不進則退</title> </head> <b

python學習之網站的編寫(HTMLCSSJS)(十二)----------CSS邊框的編寫

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>逆水行舟不進則退</title> </head> <b

python學習之網站的編寫(HTMLCSSJS)(十一)----------如何利用其它html檔案中的CSS(也就是可以將共同的地方提取出來放大一個檔案中利於使用)

首先說一下它的具體用處,我們已經知道,當我們寫一個html檔案的時候,不同的標籤想用相同的版式的時候,我們可以將它提取出來,然後再用一些選擇器進行應用,比如class選擇器。但是,但我們編寫多個html檔案中的時候,多個檔案都想用一些相同的版式該怎麼辦呢? 那麼就引入了這種連線的方式,首先寫一個

python學習之網站的編寫(HTMLCSSJS)(十)----------CSS中用的最多的class選擇器批量的為一些標籤設定相同的版式

選擇器有很多種,有id選擇器,div選擇器,層級選擇器,組合選擇器等等,然而,用的最多的就是class選擇器,它的作用是為下面所有符合class規則的標籤設定上相同的版式。 步驟: 1.在頭部編寫<style>標籤,點+class選擇器的名稱(也就是下面需要選擇的class),然

python學習之網站的編寫(HTMLCSSJS)(九)----------table標籤表格的實現

 table標籤,裡邊的tr表示行,td表示列。 程式碼: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>逆水行

python學習之網站的編寫(HTMLCSSJS)(八)----------label標籤點選label標籤的文字將編輯的游標移過來

 如果不加label的話,只設置值的話,點選文字是不能將編輯的游標移過來的,必須將id連線上之後,才可以實現,點選文字就可以將編輯的游標移過來。 實現結果: 程式碼: <!DOCTYPE html> <html lang="en"> <hea

python學習之網站的編寫(HTMLCSSJS)(七)----------以列表條目的方式顯示

話不多說,直接上圖 實現的程式碼及解釋: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>逆水行舟不進則退</t

FLEXJS資料互動以及Google外掛IFrame的使用

       最近因為專案需要,用到的flex,同時需要與js做資料互動,同時還用到了Google的外掛IFrame,總結一點點自己的使用心得,其中很多資料都是在網上Google到的。     FLEX呼叫

htmlcssjs實現音樂播放含音訊特效和歌詞

前端播放器樣例  有需要的小夥伴直接用就行:https://download.csdn.net/download/qq_34042417/10669205 實現思路: 1.載入完頁面後請求等到歌曲,歌詞檔案,要實現歌詞跟歌曲滾動則要求歌詞是lrc格式。 2.對歌詞處理,處理

python學習之網站的編寫(HTMLCSSJS)(一)---------------------------------------初識(初學者需瞭解)

首先推薦一款很好的python編譯軟體pycharm,但凡接觸過python的人對它一定不是很陌生,在這裡我們就可以編輯一些瀏覽器認識的html檔案,創造出我們喜歡的網站頁面,在pycharm中建立一個html檔案是下面這樣的,然後我們會對其一句一句的解釋。 <!DO