內聯JavaScript應該放在HTML的哪一個位置

寫在前面

本文首發於公衆號:符合預期的CoyPan

內聯JavaScript在如今的前端項目中是比較常見的,好比一些全局函數,全局統計邏輯等,咱們可能會之內聯JavaScript的方式寫在HTML裏。那麼,內聯JavaScript最好應該放在哪裏呢?javascript

頁面渲染流程

首先來看看這個問題:頁面是怎麼渲染的?大體流程以下:css

clipboard.png

clipboard.png

頁面的渲染是一個複雜的過程,這裏就再也不詳細說了。簡單總結一下,就是使用HTML構建DOM樹,CSS構建CSSOM,二者結合生成Render Tree,而後再進行渲染。html

推薦幾篇值得收藏,反覆閱讀的文章:前端

https://developers.google.com...java

https://developers.google.com...jquery

https://developers.google.com...web

https://developers.google.com...bootstrap

https://developers.google.com...瀏覽器

內聯JS的位置

本文僅僅討論在通常的狀況下,內聯JS應該放在哪一個位置。首先,下面兩點能夠算是【共識】:網絡

  1. JS儘可能放在HTML底部。
  2. CSS儘可能放在HTML頭部。

JS放在底部是爲了防止阻塞DOM的解析,CSS放在頭部是爲了儘早完成CSSOM的構建,從而儘早paint頁面。下面是一個常見的頁面的HTML代碼:

<html>
    <head>
        <link href="xxx.css" rel="stylesheet">
    </head>
    <body>
          <main>....</main>
        <script src="xxx.js"></script>
    </body>
</html>

假如咱們有一段內聯的、須要提早加載的、JS統計邏輯代碼,很天然的,會把內聯JS放在head裏。那麼是放在css前面,仍是後面呢?這是本文將要闡述的問題。我作了兩個實驗來看看兩個位置下的頁面渲染流程。爲了突出實驗效果,我模擬的是3g下的網速。

內聯JS在CSS以前

代碼:

<html>
    <head>
          <script type="text/javascript">
            for (var i = 0; i < 100000000; i++) {}
        </script>
        <link href="https://cdn.bootcss.com/twitter-bootstrap/4.3.1/css/bootstrap-grid.css" rel="stylesheet">
    </head>
    <body>
        <p>hello word_1</p>
        <p>hello word_2</p>
        <p>hello word_3</p>
        <p>hello word_4</p>
        <p>hello word_5</p>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
    </body>
</html>

timeline以下:

圖片描述

eventlog以下:

圖片描述

從上面兩個圖能夠看到,開始解析HTML後,會開始執行內聯JS,而且發起網絡請求下載CSS和JS文件,當CSS下載完成後,便開始進入渲染。

內聯JS在CSS後

代碼:

<html>
    <head>
        <link href="https://cdn.bootcss.com/twitter-bootstrap/4.3.1/css/bootstrap-grid.css" rel="stylesheet">
        <script type="text/javascript">
            console.log(document.getElementById, window);
            for (var i = 0; i < 100000000; i++) {}
        </script>
    </head>
    <body>
        <p>hello word_1</p>
        <p>hello word_2</p>
        <p>hello word_3</p>
        <p>hello word_4</p>
        <p>hello word_5</p>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
    </body>
</html>

timeline以下:

圖片描述

eventlog以下:

圖片描述

從上面兩個圖能夠看到,瀏覽器開始解析HTML後,會發起網絡請求下載JS和CSS,當CSS下載完成後,纔會繼續執行內聯JS,頁面的渲染被推遲了,推遲的時間就是內聯JS的執行時間。

實驗小結
  1. 瀏覽器解析HTML的時候,會對整個HTML進行『preload scanner』,提早發起網絡請求,下載外鏈資源,並非解析到對應標籤纔會進行下載。而外鏈下載這個過程是由瀏覽器進程的網絡線程完成的,不會阻塞當前渲染器進程的主線程邏輯。
  2. JS會阻塞HTML的解析。內聯JS在CSS前面的時候,執行內聯JS能夠和網絡請求並行執行,執行完內聯JS後會繼續解析HTML,而且在CSS文件下載完成後,選擇合適的時機進行渲染。而內聯JS在CSS後面的時候,因爲考慮到內聯JS可能會修改CSSOM,因此主線程會暫停,直到CSS下載完成,生成CSSOM後,纔會繼續執行內聯JS、解析HTML。

結論

對於一些全局函數,全局統計邏輯等,咱們每每會之內聯JS的形式放在HTML內的head裏。此時,最好把內聯JS放在外鏈CSS以前,以提升首屏速度,至少不會拖慢首屏速度。

寫在後面

本文聚焦探索了內聯JS在HTML內的最佳位置。網上關於頁面渲染流程的文章不少,而本身去親自實踐後,才能更好的理解整個渲染流程。符合預期。


圖片描述

相關文章
相關標籤/搜索