最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JS、CSS以及img對(duì)DOMContentLoaded事件的影響

 更新時(shí)間:2014年08月12日 16:47:23   投稿:mdxy-dxy  
最近在做性能有關(guān)的數(shù)據(jù)上報(bào),發(fā)現(xiàn)了兩個(gè)非常有意思的東西:Chrome開(kāi)發(fā)者工具的Timeline分析面板,以及DOMContentLoaded事件。一個(gè)是強(qiáng)大的令人發(fā)指的性能分析工具,一個(gè)是重要的性能指標(biāo),于是就用Timeline對(duì)DOMContentLoaded事件進(jìn)行了一番研究

前端的純技術(shù)就是對(duì)規(guī)范的認(rèn)知

什么是DOMContentLoaded事件?

首先想到的是查看W3C的HTML5規(guī)范,DOMContentLoaded事件在什么時(shí)候觸發(fā):

Once the user agent stops parsing the document, the user agent must run the following steps:
1. Set the current document readiness to “interactive” and the insertion point to undefined.
Pop all the nodes off the stack of open elements.
2. If the list of scripts that will execute when the document has finished parsing is not empty, run these substeps:
2.1 Spin the event loop until the first script in the list of scripts that will execute when the document has finished parsing has its “ready to be parser-executed” flag set and the parser's Document has no style sheet that is blocking scripts.
2.2 Execute the first script in the list of scripts that will execute when the document has finished parsing.
2.3 Remove the first script element from the list of scripts that will execute when the document has finished parsing (i.e. shift out the first entry in the list).
2.4 If the list of scripts that will execute when the document has finished parsing is still not empty, repeat these substeps again from substep 1.
3. Queue a task to fire a simple event that bubbles named DOMContentLoaded at the Document.

規(guī)范總是那么的晦澀,但至少有一點(diǎn)是可以明確了的,就是在JS(不包括動(dòng)態(tài)插入的JS)執(zhí)行完之后,才會(huì)觸發(fā)DOMContentLoaded事件。

接下來(lái)看看MDN上有關(guān)DOMContentLoaded事件的文檔

The DOMContentLoaded event is fired when the document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading
Note: Stylesheet loads block script execution, so if you have a <script> after a <link rel="stylesheet" ...>, the page will not finish parsing – and DOMContentLoaded will not fire – until the stylesheet is loaded.

這么看來(lái),至少可以得出這么一個(gè)理論:DOMContentLoaded事件本身不會(huì)等待CSS文件、圖片、iframe加載完成。
它的觸發(fā)時(shí)機(jī)是:加載完頁(yè)面,解析完所有標(biāo)簽(不包括執(zhí)行CSS和JS),并如規(guī)范中所說(shuō)的設(shè)置 interactive 和執(zhí)行每個(gè)靜態(tài)的script標(biāo)簽中的JS,然后觸發(fā)。
而JS的執(zhí)行,需要等待位于它前面的CSS加載(如果是外聯(lián)的話(huà))、執(zhí)行完成,因?yàn)镴S可能會(huì)依賴(lài)位于它前面的CSS計(jì)算出來(lái)的樣式。

實(shí)踐是檢驗(yàn)真理的唯一標(biāo)準(zhǔn)

實(shí)驗(yàn)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" rel="external nofollow" rel="external nofollow" >
</head>
<body>
  <p>Content</p>
  <img src="./img/chrome-girl.jpg">
</body>
</html>

71fca778-a249-11e3-8824-2aae4440c857

圖一

如果頁(yè)面中沒(méi)有script標(biāo)簽,DOMContentLoaded事件并沒(méi)有等待CSS文件、圖片加載完成。

Chrome開(kāi)發(fā)者工具的Timeline面板可以幫我們記錄下瀏覽器的一舉一動(dòng)。圖一中紅色小方框中的藍(lán)線(xiàn),表示DOMContentLoaded事件,它右邊的紅線(xiàn)和綠線(xiàn)分別表示load事件和First paint,鼠標(biāo)hover在這些線(xiàn)露出灰色方框下面的一小部分時(shí)就會(huì)出現(xiàn)帶有說(shuō)明文字的tips(這交互夠反人類(lèi)的對(duì)吧!)。

實(shí)驗(yàn)2:DOMContentLoaded事件需要等待JS執(zhí)行完才觸發(fā)

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" rel="external nofollow" rel="external nofollow" >
  <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');

dcf399e8-a252-11e3-92c1-c3dbad820909

圖二

如果頁(yè)面中靜態(tài)的寫(xiě)有script標(biāo)簽,DOMContentLoaded事件需要等待JS執(zhí)行完才觸發(fā)。

而script標(biāo)簽中的JS需要等待位于其前面的CSS的加載完成。

console.timeStamp() 可以向Timeline中添加一條記錄,并對(duì)應(yīng)上方的一條黃線(xiàn)。

從圖二中可以看出,在CSS之前的JS立刻得到了執(zhí)行,而在CSS之后的JS,需要等待CSS加載完后才執(zhí)行,比較明顯的是main.js早就加載完了,但還是要等main.css加載完才能執(zhí)行。而DOMContentLoaded事件,則是在JS執(zhí)行完后才觸發(fā)?;瑒?dòng)Timeline面板中表示展示區(qū)域的滑塊,如圖三,放大后即可看到表示DOMContentLoaded事件的藍(lán)線(xiàn)(之前跟黃線(xiàn)和綠線(xiàn)靠的太近了),當(dāng)然,通過(guò) console.timeStamp() 向TimeLine中添加的記錄也可證明其觸發(fā)時(shí)間。

910b5c2c-a253-11e3-995d-e19fb254cf4e

圖三

現(xiàn)代瀏覽器會(huì)并發(fā)的預(yù)加載CSS, JS,也就是一開(kāi)始就并發(fā)的請(qǐng)求這些資源,但是,執(zhí)行CSS和JS的順序還是按原來(lái)的依賴(lài)順序(JS的執(zhí)行要等待位于其前面的CSS和JS加載、執(zhí)行完)。先加載完成的資源,如果其依賴(lài)還沒(méi)加載、執(zhí)行完,就只能等著。

實(shí)驗(yàn)3:img何時(shí)開(kāi)始解碼、繪制?


從圖三中我們可以發(fā)現(xiàn)一個(gè)有趣的地方:img的請(qǐng)求老早就發(fā)出了,但延遲了一段時(shí)間才開(kāi)始解碼。如圖二、圖三中的紅框所示,截圖中只框出了一部分表示解碼的記錄,而實(shí)際上這些表示解碼的記錄一直持續(xù)到img加載結(jié)束,如圖四所示,img是一邊加載一邊解碼的:

7384a57a-a256-11e3-9c4a-b857956eaeed

圖三

現(xiàn)代瀏覽器會(huì)并發(fā)的預(yù)加載CSS, JS,也就是一開(kāi)始就并發(fā)的請(qǐng)求這些資源,但是,執(zhí)行CSS和JS的順序還是按原來(lái)的依賴(lài)順序(JS的執(zhí)行要等待位于其前面的CSS和JS加載、執(zhí)行完)。先加載完成的資源,如果其依賴(lài)還沒(méi)加載、執(zhí)行完,就只能等著。

實(shí)驗(yàn)3:img何時(shí)開(kāi)始解碼、繪制?

從圖三中我們可以發(fā)現(xiàn)一個(gè)有趣的地方:img的請(qǐng)求老早就發(fā)出了,但延遲了一段時(shí)間才開(kāi)始解碼。如圖二、圖三中的紅框所示,截圖中只框出了一部分表示解碼的記錄,而實(shí)際上這些表示解碼的記錄一直持續(xù)到img加載結(jié)束,如圖四所示,img是一邊加載一邊解碼的:

7384a57a-a256-11e3-9c4a-b857956eaeed
圖四

抱著“猜想——驗(yàn)證”的想法,我猜想這是因?yàn)閕mg這個(gè)資源是否需要展現(xiàn)出來(lái),需要等 所有的JS和CSS的執(zhí)行完 才知道,因?yàn)閙ain.js可能會(huì)執(zhí)行某些DOM操作,比如刪除這個(gè)img元素,或者修改其src屬性,而CSS可能會(huì)將其 display: none 。

image
圖五

image
圖六

image
圖七

圖五中沒(méi)有JS和CSS,img的數(shù)據(jù)一接收到就馬上開(kāi)始解碼了。
圖六中沒(méi)有JS,但img要等到CSS加載完才開(kāi)始解碼。
圖七的代碼跟圖六的代碼唯一的區(qū)別是CSS把img給 display: none; ,這使得img雖然請(qǐng)求了,但根本沒(méi)有進(jìn)行解碼。
這說(shuō)明,img是否需要解碼、繪圖(paint)出來(lái),確實(shí)需要等CSS加載、執(zhí)行完才能知道。也就是說(shuō),CSS會(huì)阻塞img的展現(xiàn)!那么JS呢?

image
圖八

圖八對(duì)應(yīng)的代碼:

<!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而沒(méi)有CSS的頁(yè)面中,img居然能夠在收到數(shù)據(jù)后就立刻開(kāi)始解碼、繪圖(paint),也就是說(shuō),JS并沒(méi)有阻塞img的展現(xiàn)!這跟我們以前理解的JS會(huì)阻塞img資源的傳統(tǒng)觀(guān)念不太一樣,看來(lái)Chrome對(duì)img的加載和展現(xiàn)做了新的優(yōu)化。

我們常用的jQuery的 $(document).ready() 方法,就是對(duì)DOMContentLoaded事件的監(jiān)聽(tīng)(當(dāng)然,其內(nèi)部還會(huì)通過(guò)模擬DOMContentLoaded事件和監(jiān)聽(tīng)onload事件來(lái)提供降級(jí)方案)。通常推薦在DOMContentLoaded事件觸發(fā)的時(shí)候?yàn)镈OM元素注冊(cè)事件。所以盡快的讓DOMContentLoaded事件觸發(fā),就意味著能夠盡快讓頁(yè)面可交互:

減小CSS文件體積,把單個(gè)CSS文件分成幾個(gè)文件以并行加載,減少CSS對(duì)JS的阻塞時(shí)間

次要的JS文件,通過(guò)動(dòng)態(tài)插入script標(biāo)簽來(lái)加載(動(dòng)態(tài)插入的script標(biāo)簽不阻塞DOMContentLoaded事件的觸發(fā))

CSS中使用的精靈圖,可以利用對(duì)img的預(yù)加載,放在html中跟CSS文件一起加載

在做實(shí)驗(yàn)的過(guò)程中,感覺(jué)Chrome開(kāi)發(fā)者工具的Timeline面板非常強(qiáng)大,瀏覽器的一舉一動(dòng)都記錄下來(lái)。以前我們前端開(kāi)發(fā)要想理解、探索瀏覽器的內(nèi)部行為,或者摸著石頭過(guò)河的做黑盒測(cè)試,或者事倍功半的研究瀏覽器源碼,唯一高效點(diǎn)的做法就是學(xué)習(xí)別人的研究經(jīng)驗(yàn),看老外的文章,但瀏覽器的發(fā)展日新月異(比如這次實(shí)驗(yàn)發(fā)現(xiàn)的JS不阻塞img的展現(xiàn)),別人的經(jīng)驗(yàn)始終不是最新、最適合的,關(guān)鍵是要結(jié)合自己的業(yè)務(wù)、需求場(chǎng)景,有針對(duì)性的做分析和優(yōu)化。

PS.
以上測(cè)試環(huán)境為windows/chrome,并用Fiddler模擬慢速網(wǎng)絡(luò)

相關(guān)文章

  • javascript中使用css需要注意的地方小結(jié)

    javascript中使用css需要注意的地方小結(jié)

    javascript中使用css需要注意的地方小結(jié),注意保留字問(wèn)題。
    2010-09-09
  • 教大家輕松制作Bootstrap漂亮表格(table)

    教大家輕松制作Bootstrap漂亮表格(table)

    這篇文章主要為大家詳細(xì)介紹了Bootstrap輕松制作漂亮表格table的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • 利用uni-app開(kāi)發(fā)App的超簡(jiǎn)易教程

    利用uni-app開(kāi)發(fā)App的超簡(jiǎn)易教程

    uni-app是一個(gè)使用Vue.js開(kāi)發(fā)所有前端應(yīng)用的框架,開(kāi)發(fā)者編寫(xiě)一套代碼,可發(fā)布到iOS、Android、Web(響應(yīng)式)、以及各種小程序,下面這篇文章主要給大家介紹了關(guān)于如何利用uni-app開(kāi)發(fā)App的相關(guān)資料,需要的朋友可以參考下
    2022-11-11
  • JS來(lái)動(dòng)態(tài)的修改url實(shí)現(xiàn)對(duì)url的增刪查改

    JS來(lái)動(dòng)態(tài)的修改url實(shí)現(xiàn)對(duì)url的增刪查改

    通過(guò)get方式提交post表單等方式來(lái)動(dòng)態(tài)修改url存在諸多的不妥,因此,想到了通過(guò)JS來(lái)動(dòng)態(tài)的修改url,來(lái)實(shí)現(xiàn)對(duì)url的增刪查改
    2014-09-09
  • 如何用js將blob為pcm格式轉(zhuǎn)換為MP3格式

    如何用js將blob為pcm格式轉(zhuǎn)換為MP3格式

    要將PCM文件轉(zhuǎn)換為MP3文件,您可以使用Js實(shí)現(xiàn),這篇文章主要給大家介紹了關(guān)于如何用js將blob為pcm格式轉(zhuǎn)換為MP3格式的相關(guān)資料,需要的朋友可以參考下
    2023-11-11
  • JavaScript監(jiān)聽(tīng)和禁用瀏覽器回車(chē)事件實(shí)例

    JavaScript監(jiān)聽(tīng)和禁用瀏覽器回車(chē)事件實(shí)例

    這篇文章主要介紹了JavaScript監(jiān)聽(tīng)和禁用瀏覽器回車(chē)事件實(shí)例,本文直接給出示例代碼,需要的朋友可以參考下
    2015-01-01
  • Bootstrap3 datetimepicker控件使用實(shí)例

    Bootstrap3 datetimepicker控件使用實(shí)例

    這篇文章主要為大家詳細(xì)介紹了Bootstrap3 datetimepicker控件使用實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • js使用文檔就緒函數(shù)動(dòng)態(tài)改變頁(yè)面內(nèi)容示例【innerHTML、innerText】

    js使用文檔就緒函數(shù)動(dòng)態(tài)改變頁(yè)面內(nèi)容示例【innerHTML、innerText】

    這篇文章主要介紹了js使用文檔就緒函數(shù)動(dòng)態(tài)改變頁(yè)面內(nèi)容,結(jié)合實(shí)例形式分析了JavaScript使用innerHTML、innerText函數(shù)動(dòng)態(tài)操作頁(yè)面元素相關(guān)使用技巧,需要的朋友可以參考下
    2019-11-11
  • JavaScript的懶加載處理的方式

    JavaScript的懶加載處理的方式

    懶加載是一種優(yōu)化技術(shù),它可以延遲加載某些資源,直到它們真正需要被使用的時(shí)候才進(jìn)行加載,實(shí)現(xiàn)懶加載的方法一般分為兩種:基于 Intersection Observer API 的懶加載和基于滾動(dòng)事件的懶加載,本文給大家介紹JavaScript的懶加載處理方式,感興趣的朋友一起看看吧
    2023-10-10
  • javascript 選擇文件夾對(duì)話(huà)框(web)

    javascript 選擇文件夾對(duì)話(huà)框(web)

    web程序開(kāi)發(fā)中經(jīng)常會(huì)遇見(jiàn)選擇文件夾的時(shí)候,這對(duì)于web程序員是一件麻煩的事情,由于本地安全限制JS不能訪(fǎng)問(wèn)本地文件,所以選擇文件夾一般都避而不談,筆者在寫(xiě)一個(gè)程序的時(shí)候也遇見(jiàn)了同樣的問(wèn)題,開(kāi)始嘗試使用JS來(lái)遍歷文件,結(jié)果都沒(méi)有成功
    2009-07-07

最新評(píng)論

包头市| 金山区| 宁国市| 衡阳市| 永昌县| 宜丰县| 梁山县| 张掖市| 简阳市| 仪陇县| 奇台县| 洛南县| 五原县| 平定县| 定南县| 穆棱市| 克拉玛依市| 海南省| 临澧县| 邛崃市| 巧家县| 个旧市| 萨迦县| 合作市| 岳普湖县| 伊宁县| 浠水县| 年辖:市辖区| 武邑县| 衡水市| 藁城市| 乌苏市| 阳谷县| 攀枝花市| 富民县| 西乡县| 图片| 江川县| 青河县| 泰州市| 色达县|