Skip to content

JavaScript 寫在哪裡?script 標籤與 defer、async 差異

JavaScript 寫在哪裡:script、defer 與 async

JavaScript 可以寫在哪些地方呢?其實,可以寫在任何地方。當然,造成後續的狀況也會不一樣。基本上,依狀況不同,我們可寫在三個地方,如下:

  • 單一文件。
  • 標籤內。
  • 外部引入。

小提醒

瀏覽器遇到 <script> 標籤時,會停止渲染 HTML 文件,先執行 <script> 裡面的 JavaScript 程式碼,等到執行完畢後,才會繼續渲染接下來的 HTML 文件。

因此,早期年代常會將 <script> 標籤擺放在 </body> 前面,以確保所有 DOM 元素都已建立完成,再進行 JavaScript 的下載、執行。

單一文件

<head><body> 中產生 <script> 標籤區域並寫在該標籤當中。

html
<script>
  console.log("寫在這裡");
</script>

這種寫法最快,寫個小範例、驗證一段語法很方便;缺點是程式碼與頁面綁在一起,多個頁面要共用同一段邏輯時只能複製貼上,也沒辦法被瀏覽器快取。

標籤內

在標籤的屬性中,例如:onloadonclick 這類 on 開頭的屬性。

html
<body onload="console.log('寫在這裡')">
  ...
</body>

注意

這種寫法就是 DOM Level 0 的事件綁定方式,實務上已不建議使用:HTML 與程式邏輯綁得太死、一個事件只能綁一個函式,也容易被植入惡意程式碼。改用 addEventListener()綁定事件 才是現在的做法。

外部引入

<head><body> 中以 src 屬性引入外部的 .js 檔案。

html
<script src="檔案名稱.js"></script>

這是實務上的主要寫法:同一份檔案能被多個頁面共用、可以被瀏覽器快取,也方便交給版本控制與打包工具處理。

小提醒

src 屬性時,<script> 標籤內部就不要再寫程式碼,裡面的內容會被忽略。要兩種都用,請分成兩個 <script> 標籤。

使用 defer、async 加速網頁載入

使用 deferasync 屬性可以加速網頁載入時間。當瀏覽器在解析 HTML 時,順序是由上而下、由左而右。因此,使用這兩個屬性,於下載時並不會阻擋 HTML 的 DOM 渲染。

html
<script defer src="檔案名稱.js"></script>
<script async src="檔案名稱.js"></script>

但這兩個屬性又有什麼差別呢?

defer

  • 整個網頁都渲染完畢,也就是 DOM 都建立完成之後才會開始執行 JavaScript。
  • 會依照 HTML 的順序執行,如果已下載完畢也會等前面的 JavaScript 執行完畢才開始執行自己的 JavaScript。

async

  • 不會等 DOM 建立完成,只要下載完畢就直接執行 JavaScript。
  • 不會依照 HTML 的順序執行,誰先下載完誰先執行。

三種載入方式的比較

寫法下載時是否阻擋解析執行時機是否保證順序
<script>立刻執行
<script defer>不會HTML 解析完成後
<script async>不會下載完就執行

該選哪一個

  • 需要操作 DOM,或多支檔案之間有依賴關係 → 用 defer
  • 完全獨立、與頁面其他程式無關的腳本,例如:流量分析 → 可以用 async
  • 兩個屬性都寫時,async 優先生效;瀏覽器不支援時才退回 defer

載入流程對照

方式流程
傳統畫面渲染 → 停止渲染 → 請求 JavaScript → 等待 → 執行 → 繼續渲染
defer畫面渲染(同時下載 JavaScript)→ 渲染完成 → 執行
async畫面渲染(同時下載 JavaScript)→ 下載完成即停止渲染並執行 → 繼續渲染

常見問題

JavaScript 應該寫在 head 還是 body 結尾?

現在建議寫在 <head> 並加上 defer。早期把 <script> 放在 </body> 前是為了確保 DOM 已建立,而 defer 同樣能保證這件事,還能讓瀏覽器提早開始下載檔案。

defer 與 async 有什麼差別?

兩者的下載都不會阻擋 HTML 解析。defer 會等 HTML 解析完成才執行,並保證依照文件中的順序執行;async 則是下載完就立刻執行,順序不固定,執行時仍會暫停解析。

為什麼 script 標籤會讓網頁變慢?

瀏覽器解析 HTML 遇到沒有 deferasync<script> 時,必須先下載並執行完裡面的程式碼才會繼續解析,這段等待時間畫面就停在原地,也就是所謂的 阻塞渲染

可以把 JavaScript 寫在 HTML 的屬性裡嗎?

語法上可以,例如:onclick 屬性,但不建議。這種寫法讓 HTML 與程式邏輯綁死、一個事件只能綁一個函式,也較容易成為被注入惡意程式碼的破口,細節可參考 DOM 事件級別

什麼情況適合用 async?

適合與頁面其他程式無依賴關係的獨立腳本,例如:流量分析、廣告追蹤。只要腳本之間有先後依賴,或需要操作 DOM,就改用 defer

延伸閱讀