<strike id="iokis"><blockquote id="iokis"></blockquote></strike>
  • <dl id="iokis"><del id="iokis"></del></dl>
    \n  

    Content<\/p>\n \"JS、CSS以及img對(duì)DOMContentLoaded事件的影響_javascript技巧\"\n<\/body>\n<\/html><\/pre>\n<\/div>\n

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

    亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

    首頁(yè) web前端 js教程 JS、CSS以及img對(duì)DOMContentLoaded事件的影響_javascript技巧

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

    May 16, 2016 pm 04:39 PM
    img

    前端的純技術(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 <font face="NSimsun"><script></script></font> after a <font face="NSimsun"><link rel="stylesheet" ...></font>, 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è)置 <font face="NSimsun">interactive</font> 和執(zhí)行每個(gè)靜態(tài)的script標(biāo)簽中的JS,然后觸發(fā)。
    而JS的執(zhí)行,需要等待位于它前面的CSS加載(如果是外聯(lián)的話)、執(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="/static/imghw/default1.png"  data-src="./img/chrome-girl.jpg"  class="lazy" alt="JS、CSS以及img對(duì)DOMContentLoaded事件的影響_javascript技巧" >
    </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)線,表示DOMContentLoaded事件,它右邊的紅線和綠線分別表示load事件和First paint,鼠標(biāo)hover在這些線露出灰色方框下面的一小部分時(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="/static/imghw/default1.png"  data-src="./img/chrome-girl.jpg"  class="lazy" alt="JS、CSS以及img對(duì)DOMContentLoaded事件的影響_javascript技巧" >
      <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)上方的一條黃線。

    從圖二中可以看出,在CSS之前的JS立刻得到了執(zhí)行,而在CSS之后的JS,需要等待CSS加載完后才執(zhí)行,比較明顯的是main.js早就加載完了,但還是要等main.css加載完才能執(zhí)行。而DOMContentLoaded事件,則是在JS執(zhí)行完后才觸發(fā)?;瑒?dòng)Timeline面板中表示展示區(qū)域的滑塊,如圖三,放大后即可看到表示DOMContentLoaded事件的藍(lá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ì)將其 <font face="NSimsun">display: none</font> 。

    image
    圖五

    image
    圖六

    image
    圖七

    圖五中沒(méi)有JS和CSS,img的數(shù)據(jù)一接收到就馬上開(kāi)始解碼了。
    圖六中沒(méi)有JS,但img要等到CSS加載完才開(kāi)始解碼。
    圖七的代碼跟圖六的代碼唯一的區(qū)別是CSS把img給 <font face="NSimsun">display: none;</font> ,這使得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="/static/imghw/default1.png"  data-src="./img/chrome-girl.jpg"  class="lazy" alt="JS、CSS以及img對(duì)DOMContentLoaded事件的影響_javascript技巧" >
      <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)觀念不太一樣,看來(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ò)

    本站聲明
    本文內(nèi)容由網(wǎng)友自發(fā)貢獻(xiàn),版權(quán)歸原作者所有,本站不承擔(dān)相應(yīng)法律責(zé)任。如您發(fā)現(xiàn)有涉嫌抄襲侵權(quán)的內(nèi)容,請(qǐng)聯(lián)系admin@php.cn

    熱AI工具

    Undress AI Tool

    Undress AI Tool

    免費(fèi)脫衣服圖片

    Undresser.AI Undress

    Undresser.AI Undress

    人工智能驅(qū)動(dòng)的應(yīng)用程序,用于創(chuàng)建逼真的裸體照片

    AI Clothes Remover

    AI Clothes Remover

    用于從照片中去除衣服的在線人工智能工具。

    Clothoff.io

    Clothoff.io

    AI脫衣機(jī)

    Video Face Swap

    Video Face Swap

    使用我們完全免費(fèi)的人工智能換臉工具輕松在任何視頻中換臉!

    熱工具

    記事本++7.3.1

    記事本++7.3.1

    好用且免費(fèi)的代碼編輯器

    SublimeText3漢化版

    SublimeText3漢化版

    中文版,非常好用

    禪工作室 13.0.1

    禪工作室 13.0.1

    功能強(qiáng)大的PHP集成開(kāi)發(fā)環(huán)境

    Dreamweaver CS6

    Dreamweaver CS6

    視覺(jué)化網(wǎng)頁(yè)開(kāi)發(fā)工具

    SublimeText3 Mac版

    SublimeText3 Mac版

    神級(jí)代碼編輯軟件(SublimeText3)

    熱門(mén)話題

    Laravel 教程
    1597
    29
    PHP教程
    1488
    72
    如何在node.js中提出HTTP請(qǐng)求? 如何在node.js中提出HTTP請(qǐng)求? Jul 13, 2025 am 02:18 AM

    在Node.js中發(fā)起HTTP請(qǐng)求有三種常用方式:使用內(nèi)置模塊、axios和node-fetch。1.使用內(nèi)置的http/https模塊無(wú)需依賴(lài),適合基礎(chǔ)場(chǎng)景,但需手動(dòng)處理數(shù)據(jù)拼接和錯(cuò)誤監(jiān)聽(tīng),例如用https.get()獲取數(shù)據(jù)或通過(guò).write()發(fā)送POST請(qǐng)求;2.axios是基于Promise的第三方庫(kù),語(yǔ)法簡(jiǎn)潔且功能強(qiáng)大,支持async/await、自動(dòng)JSON轉(zhuǎn)換、攔截器等,推薦用于簡(jiǎn)化異步請(qǐng)求操作;3.node-fetch提供類(lèi)似瀏覽器fetch的風(fēng)格,基于Promise且語(yǔ)法簡(jiǎn)單

    JavaScript數(shù)據(jù)類(lèi)型:原始與參考 JavaScript數(shù)據(jù)類(lèi)型:原始與參考 Jul 13, 2025 am 02:43 AM

    JavaScript的數(shù)據(jù)類(lèi)型分為原始類(lèi)型和引用類(lèi)型。原始類(lèi)型包括string、number、boolean、null、undefined和symbol,其值不可變且賦值時(shí)復(fù)制副本,因此互不影響;引用類(lèi)型如對(duì)象、數(shù)組和函數(shù)存儲(chǔ)的是內(nèi)存地址,指向同一對(duì)象的變量會(huì)相互影響。判斷類(lèi)型可用typeof和instanceof,但需注意typeofnull的歷史問(wèn)題。理解這兩類(lèi)差異有助于編寫(xiě)更穩(wěn)定可靠的代碼。

    JavaScript時(shí)間對(duì)象,某人構(gòu)建了一個(gè)eactexe,在Google Chrome上更快的網(wǎng)站等等 JavaScript時(shí)間對(duì)象,某人構(gòu)建了一個(gè)eactexe,在Google Chrome上更快的網(wǎng)站等等 Jul 08, 2025 pm 02:27 PM

    JavaScript開(kāi)發(fā)者們,大家好!歡迎閱讀本周的JavaScript新聞!本周我們將重點(diǎn)關(guān)注:Oracle與Deno的商標(biāo)糾紛、新的JavaScript時(shí)間對(duì)象獲得瀏覽器支持、GoogleChrome的更新以及一些強(qiáng)大的開(kāi)發(fā)者工具。讓我們開(kāi)始吧!Oracle與Deno的商標(biāo)之爭(zhēng)Oracle試圖注冊(cè)“JavaScript”商標(biāo)的舉動(dòng)引發(fā)爭(zhēng)議。Node.js和Deno的創(chuàng)建者RyanDahl已提交請(qǐng)?jiān)笗?shū),要求取消該商標(biāo),他認(rèn)為JavaScript是一個(gè)開(kāi)放標(biāo)準(zhǔn),不應(yīng)由Oracle

    什么是緩存API?如何與服務(wù)人員使用? 什么是緩存API?如何與服務(wù)人員使用? Jul 08, 2025 am 02:43 AM

    CacheAPI是瀏覽器提供的一種緩存網(wǎng)絡(luò)請(qǐng)求的工具,常與ServiceWorker配合使用,以提升網(wǎng)站性能和離線體驗(yàn)。1.它允許開(kāi)發(fā)者手動(dòng)存儲(chǔ)如腳本、樣式表、圖片等資源;2.可根據(jù)請(qǐng)求匹配緩存響應(yīng);3.支持刪除特定緩存或清空整個(gè)緩存;4.通過(guò)ServiceWorker監(jiān)聽(tīng)fetch事件實(shí)現(xiàn)緩存優(yōu)先或網(wǎng)絡(luò)優(yōu)先等策略;5.常用于離線支持、加快重復(fù)訪問(wèn)速度、預(yù)加載關(guān)鍵資源及后臺(tái)更新內(nèi)容;6.使用時(shí)需注意緩存版本控制、存儲(chǔ)限制及與HTTP緩存機(jī)制的區(qū)別。

    處理諾言:鏈接,錯(cuò)誤處理和承諾在JavaScript中 處理諾言:鏈接,錯(cuò)誤處理和承諾在JavaScript中 Jul 08, 2025 am 02:40 AM

    Promise是JavaScript中處理異步操作的核心機(jī)制,理解鏈?zhǔn)秸{(diào)用、錯(cuò)誤處理和組合器是掌握其應(yīng)用的關(guān)鍵。1.鏈?zhǔn)秸{(diào)用通過(guò).then()返回新Promise實(shí)現(xiàn)異步流程串聯(lián),每個(gè).then()接收上一步結(jié)果并可返回值或Promise;2.錯(cuò)誤處理應(yīng)統(tǒng)一使用.catch()捕獲異常,避免靜默失敗,并可在catch中返回默認(rèn)值繼續(xù)流程;3.組合器如Promise.all()(全成功才成功)、Promise.race()(首個(gè)完成即返回)和Promise.allSettled()(等待所有完成)

    利用Array.Prototype方法用于JavaScript中的數(shù)據(jù)操作 利用Array.Prototype方法用于JavaScript中的數(shù)據(jù)操作 Jul 06, 2025 am 02:36 AM

    JavaScript數(shù)組內(nèi)置方法如.map()、.filter()和.reduce()可簡(jiǎn)化數(shù)據(jù)處理;1).map()用于一對(duì)一轉(zhuǎn)換元素生成新數(shù)組;2).filter()按條件篩選元素;3).reduce()用于聚合數(shù)據(jù)為單一值;使用時(shí)應(yīng)避免誤用導(dǎo)致副作用或性能問(wèn)題。

    JS綜述:深入研究JavaScript事件循環(huán) JS綜述:深入研究JavaScript事件循環(huán) Jul 08, 2025 am 02:24 AM

    JavaScript的事件循環(huán)通過(guò)協(xié)調(diào)調(diào)用棧、WebAPI和任務(wù)隊(duì)列來(lái)管理異步操作。1.調(diào)用棧執(zhí)行同步代碼,遇到異步任務(wù)時(shí)交由WebAPI處理;2.WebAPI在后臺(tái)完成任務(wù)后將回調(diào)放入相應(yīng)的隊(duì)列(宏任務(wù)或微任務(wù));3.事件循環(huán)檢查調(diào)用棧是否為空,若為空則從隊(duì)列中取出回調(diào)推入調(diào)用棧執(zhí)行;4.微任務(wù)(如Promise.then)優(yōu)先于宏任務(wù)(如setTimeout)執(zhí)行;5.理解事件循環(huán)有助于避免阻塞主線程并優(yōu)化代碼執(zhí)行順序。

    了解事件在JavaScript DOM事件中冒泡和捕獲 了解事件在JavaScript DOM事件中冒泡和捕獲 Jul 08, 2025 am 02:36 AM

    事件冒泡是從目標(biāo)元素向外傳播到祖先節(jié)點(diǎn),事件捕獲則是從外層向內(nèi)傳播到目標(biāo)元素。1.事件冒泡:點(diǎn)擊子元素后,事件依次向上觸發(fā)父級(jí)元素的監(jiān)聽(tīng)器,例如點(diǎn)擊按鈕后先輸出Childclicked,再輸出Parentclicked。2.事件捕獲:設(shè)置第三個(gè)參數(shù)為true,使監(jiān)聽(tīng)器在捕獲階段執(zhí)行,如點(diǎn)擊按鈕前先觸發(fā)父元素的捕獲監(jiān)聽(tīng)器。3.實(shí)際用途包括統(tǒng)一管理子元素事件、攔截預(yù)處理和性能優(yōu)化。4.DOM事件流分為捕獲、目標(biāo)和冒泡三個(gè)階段,默認(rèn)監(jiān)聽(tīng)器在冒泡階段執(zhí)行。

    See all articles