2017-03-22 45 views
6

在延遲attirbute MDN says是否在DOMContentLoaded事件之前執行了延期腳本?

此布爾屬性被設置爲指示該腳本是爲了執行該文檔已被解析後,瀏覽器,但發射DOMContentLoaded之前。 defer屬性只能用於外部腳本。

DOMContentLoadedMDN also says

的DOMContentLoaded事件被觸發時,最初的HTML文檔完全加載和分析,不等待樣式 ...

所以DOMContentLoadedCSSOM準備好之前發射。這意味着在CSSOM準備就緒之前,推遲的腳本是執行。但如果這是真的,腳本一定不能獲得正確的css屬性值,並且不能正確應用css。但事實並非如此,我們知道所有延遲腳本都能正常工作。

  1. 所以是MDN文檔技術上不正確的?
  2. 我在哪裏可以找到DOMContentLoaded`的官方文檔?我在https://dom.spec.whatwg.org/搜索,但無法找到它。

P.S:請不就是那個google says是CSSOM執行任何內嵌javscript

enter image description here

之前建造但谷歌在技術上是不正確。在CSSOM準備好之前,內聯JavaScript被執行。從我的測試中,我發現MDN是正確的,如果js文件(延遲和非延遲)在css文件(或js內聯)之前下載,那麼在CSSOM準備好之前執行js。所以JS可能會錯誤地處理樣式。爲了避免這種情況,我們需要在所有js邏輯之前進行強制重排。

因此,如果用戶訪問我們的網站與所有的JS需要已經被緩存和css不緩存或JS被CSS之前下載的,然後他(她)可能會看到不正確呈現的頁面。爲了避免這種情況,我們應該在我們所有網站的js文件中添加強制重排。

+0

另外一個相關的討論已經在http://stackoverflow.com/q已持續/ 42891628/3429430 – user31782

回答

2

我使用延遲腳本加載。有一位很有名的網站性能大師的技術解釋很漫長。他明確指出,延期是要走的路(因爲這個和那個技術原因,得到各種數據和圖表的支持,很多人似乎都覺得這是開放性的,可以辯論,反之:異步)。

所以我開始使用它。延遲腳本具有下載異步的優點,但是可以按照提供的順序執行,這可能是異步問題(例如,您可以在供應商捆綁包之前加載應用捆綁包,因爲您不僅僅通過說出來控制異步腳本的執行順序「按此順序」)。

然而,我發現,馬上,雖然這解決了這個問題,這可能意味着,這取決於你如何搶你的包時,將CSS束未加載。所以你可以最終得到無格式的內容,這取決於你如何設置。請注意,爲了推遲,他們也說你不應該寫信給dom等。在這些腳本中(這對您的文檔而言也是有意義的)。

所以看起來你的文檔是正確的。效果很容易複製。

我該如何擺脫它;最基本的方法是這樣的:

<script src="css.bundle.js"></script> 
<script src="vendor.bundle.js" defer></script> 
<script src="angular.bundle.js" defer></script> 
<script src="app.bundle.js" defer></script> 

這可以確保在第一,所以你的主頁等的CSS負荷將出現很好的,而且也保證了(雖然所有三個加載異步) ,app.bundle將最後執行,確保所有其他依賴項都是有序的。

所以,你需要CSS的絕對最低限度的反彈應用程序,創建一個捆綁,並加載它之前,任何事情。否則,您可以將每個模塊/組件捆綁到您的CSS中,等等。

這個話題還有很多,我可能會做更多的,但是(我會試着找到參考),這是性能嚮導公然推薦的,所以我嘗試了它,它似乎非常有效我。

編輯:引人入勝,在尋找那個參考文獻(我還沒有找到)的時候,我遇到了一些關於這個主題的「專家」。這些建議差異很大。有人說異步在所有方面都遠遠勝過,有人說延遲。陪審團真的看起來是關於這個話題的,總的來說,我認爲這可能與你是如何構建你的腳本有關,而不是其中一個比另一個更好。

再次編輯:這是一些更多的證據。我使用上面簡單的加載順序在一個存根網站上運行了一個性能分析器,故意讓這些腳本幼稚,以便它們在時間線上可見。

下面是結果的SS:這裏有四個黃色框。前三個是對腳本的評估。第四個(當你在工具中將鼠標放在它上面時,這只是SS記住)是DOMContentLoaded事件(帶有紅色角的那個)。

Scripts loading/evaluating before DOMContentLoaded event

+0

'css.bundle.js'做什麼?在它上面省略'defer'會迫使瀏覽器首先下載'css resources'然後'css.bundle.js'(到現在爲止CSSOM已準備就緒),並且所有延期腳本都應該在'css.bundle.js'之後下載? – user31782

+0

CSS Bundle是您的CSS文件的捆綁版本(我使用webpack)。這個想法是將所有這些腳本/ css標籤從你的索引頁面中取出來,並將它們智能地捆綁在一起,這樣你就可以精確地控制它們的加載方式和時間。在這個示例中,假設css.bundle具有用於在加載其他腳本時設置主頁樣式的樣式。沒有推遲或異步標記的腳本將按照您放置它們的順序進行下載和評估。所以是的,這裏的css包將首先加載,然後其他所有內容都將加載到延遲(async),但這些腳本將按指定的順序進行評估(執行)。 –

+0

如果我明白延期正確。 'css.bundle'上的'defer'不會改變執行順序。我沒有使用過webpack。但我猜'css.bundle'應該添加'style'標籤來頭部和附加樣式。我的問題是,如果這是'css.bundle'然後假設'vendor.bundle.js'在'css.bundle.js'之前下載,那麼'vendor.bundle'會在CSSOM準備好之前優異嗎? – user31782

2

DOMContentLoaded可以CSSOM之前被解僱,source

的domContentLoaded事件觸發的HTML解析後不久;瀏覽器知道不會在JavaScript上阻塞,並且因爲沒有其他解析器阻塞腳本,CSSOM構造也可以並行進行。在谷歌開發者

enter image description here

文章介紹async而不是defer但在你的問題的情況下,因爲基於Steve Sourders articleperfplanet

DEFER腳本它不會改變任何東西后執行DOM Interactive。

his comment在他的文章

[...]的規範說DEFER腳本domInteractive後,但domContentLoaded之前運行。

你可以讓自己的實驗,看看下面使用defer和時間軸代碼

<!DOCTYPE html> 
<html> 
<head> 
    <meta charset="utf-8"> 
    <title>JS Bin</title> 
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/css/bootstrap.css"> 
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-material/1.1.3/angular-material.css"> 
</head> 
<body> 
    <h1>App</h1> 
    <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/js/bootstrap.js" defer></script> 
</body> 
</html> 

enter image description here

+0

我對許多繁重的樣式表執行了相同的測試,並且只使用了內嵌javascript。在下載樣式表之後並在應用樣式表(CSSOM就緒)之前觸發'DOMContentLoaded'。這意味着無需等待樣式表..._ MDN並不意味着不下載樣式表;這意味着沒有使用styelsheets。 – user31782

+0

我不確定我是否正確理解了你,但內聯腳本應該在CSSOM之後執行,而不是之前。 [如果我們用內聯腳本替換我們的外部腳本,該怎麼辦?即使腳本直接內聯到頁面中,瀏覽器也不能執行它,直到構建CSSOM。簡而言之,內聯JavaScript也是解析器阻塞。](https://developers.google.com/web/fundamentals/performance/critical-rendering-path/analyzing-crp) – hinok

+0

Hinok,這正是我所觀察到的。內聯javscript在CSSOM準備好之前執行。我在這裏提出了這個問題http://stackoverflow.com/q/42891628/3429430 – user31782

相關問題