ScarShow

< IS >

HTML 中 JavaScript 的載入問題

前言

一般在瀏覽器中對於HTML的解析順序是由上而下的,所以在傳統的網頁設計中我們一般都會將<script>標籤放置在<head></head>中,這樣能確保JavaScript盡早被執行到。

但是隨著近年來網頁不再只是網頁,而漸漸成為了Web Application,因為如此所以使用到的JavaScript就變得越來越大,這時候JavaScript的載入就是個問題。

阻塞 (Blocking)

在傳統的瀏覽器中,每當解析到了<script>標籤時瀏覽器的繪製就會停頓下來,然後去下載並執行JavaScript中的內容,過多的JavaScript內容會造成阻塞問題,便是瀏覽器停頓一段時間等待JavaScript都執行完畢後,才開始繪製剩下的網頁內容。

上面提到,一般會將<script>標前放置在<head></head>中,這會造成網頁在一片空白的情況下停頓許久。

<html>
    <head>
        <script></script>
        <script></script>
    </head>
    <body>
        <!--something-->
    </body>
</html>

所以現在會建議將<script>放置在<body></body>的尾端,等待瀏覽器將大部分的內容都繪製出來之後再去執行JavaScript,這樣比較不會造成使用者的觀感不佳。

<html>
    <head>
    </head>
    <body>

        <!--something-->

        <script></script>
        <script></script>
    </body>
</html>

async, defer 屬性

雖然可以將<script>放置在<body></body>的尾端,來減少使用者觀感不佳,但是實際上放置在尾端還是會有阻塞(Blocking)的問題,這個問題依舊沒有解決。

所以在HTML5終究提出了新的async以及defer屬性來解決阻塞(Blocking)的問題,在<script>中加上這兩個屬性就可以讓有支援的瀏覽器,以非同步的方式下載JavaScript並執行其內容。

<script src="file.js"></script>
<script src="file.js" defer></script>
<script src="file.js" async></script>

<script>,停止網頁繪製,等待JavaScript下載並執行完,再繼續網頁繪製。

<script defer>,不停止網頁繪製,JavaScript的下載會同時進行,等待網頁繪製完成會再執行JavaScript

<script async>,不停止網頁繪製,JavaScript的下載會同時進行,當JavaScript下載完成後,再停止網頁繪製並執行JavaScript,等待執行完成後再繼續網頁繪製。

Peter Beverloo在他的網誌上有繪製一張時序圖,用來說明這兩個新的屬性與傳統的載入方式有什麼不同,可參考下方連結。

RequireJS

asyncdefer屬性可以解決阻塞問題,但也引起了一個新的問題,那就是以非同步方是執行的JavaScript的執行順序並不是依照<script>在HTML上的順序,而是誰先下載好就先執行誰,如果你的JavaScript的設計在執行上有相依性的問題就有機會因為執行順序的不同而爆炸。

因此RequireJS的出現能夠解決此問題,它可以以非同步方式載入JavaScript,並且也可以解決JavaScript檔案之前的相依性問題,並讓JavaScript模組化。

在這並沒有要說明使用方式,可以參考網路上現有的文件,如下。

小結

上面提出的幾種解決方法,但是在實作時也不用全用上,依照當下的實作規模來做取捨,雖然沒有提到但是在製作Mobile Web時要更加注意JavaScript載入(以及其他多媒體檔案的載入),因3G或是Wifi並沒有比有線網路來的快速,所以網頁讀取時的停頓感會更加的放大,這點必須注意。