本篇介紹如何將 WordPress 網站的 JavaScript 改以 async 與 defer 的方式載入,改善網站的效能。
網站在建置的後期階段都會進行一些效能的校調,而 PageSpeed Insights 是 Google 所提供的網頁效能分析工具,輸入網址即可立即測試網站效能,並且還有列出各種問題以及解決方案。
「移除禁止轉譯 JavaScript」是一般網站很常見的問題,以 WordPress 架設的網站也不例外,簡單來說禁止轉譯的 JavaScript 會拖慢整個 HTML 網頁的解析,如果您的 WordPress 網站在測試之後,也出現了這個訊息(如下圖),可以依照以下的方式來調整。

async 與 defer 的差別
在進行調整之前,我們先說明一下 JavaScript 檔案的載入與 HTML 解析之間的關係,釐清這個觀念可以讓您更清楚該如何調整自己的網站設定。
一般網頁的內容主要是由 HTML 程式碼再加上 JavaScript、CSS 與圖片等等元素所構成的,而 HTML 原始碼是瀏覽器第一個階收到的資料,後續才會接著取得其他的外部的 JavaScript、CSS 與 圖片檔案,現在的瀏覽器都很聰明,可以一邊解析 HTML 一邊繪製已經解析的網頁元素,如果希望網頁可以很迅速的顯示出來,就要想辦法讓 HTML 解析的速度越快越好。
在網頁載入時,瀏覽器只要遇到普通的 JavaScript 引入檔,就會暫停 HTML 的解析動作,先去下載 JavaScript 檔並且執行,處理完 JavaScript 之後,才會繼續 HTML 的解析,而 async 與 defer 可以改變瀏覽器對於 JavaScript 引入檔的載入與執行時機。

如果加入 async 的話,會讓引入的 JavaScript 檔在背景載入(包含連線至伺服器與下載),當 JavaScript 載入完成之後,才會中斷 HTML 的解析來執行 JavaScript 的程式,這是一個比較折衷的做法,既可以加速 HTML 解析,又可以減少對於整個網頁程式的影響。
而如果使用 defer 的話,引入的 JavaScript 檔一樣會在背景載入,不過載入完成後瀏覽器會等到整個 HTML 完全解析完成後,才會執行該 JavaScript 的程式內容,所以 JavaScript 的載入與執行幾乎不會影響 HTML 的解析,但是缺點是 JavaScript 的程式內容會很慢才執行。
該用 async 還是 defer?
了解 async 與 defer 的作用之後,接下來的問題就是我們該使用哪一種載入方式比較好?以下是一些大原則:
- 如果一個 JavaScript 是自己獨立的,不需要依賴其他的 JavaScript 就可以運作,那麼就可以使用
async。 - 如果一個 JavaScript 需要依賴網頁中其他的 JavaScript 程式,則建議使用
defer。 - 如果有一個 JavaScript 檔案
file1.js需要依賴file2.js的內容才能執行,而且file2.js的檔案內容又很小的話,我們可以將file2.js的內容直接以 inline 的方式放在file1.js引入位置之前,這樣就可以讓file1.js以 async 的方式載入,又不影響相依性。
以上這些只是大原則,並不是絕對的標準,實際該怎麼使用我覺得還是要看每個 JavaScript 的性質,一般來說 async 是最常用的,它可以在盡量不影響原來的執行順序之下,加速網頁的載入與顯示。
對於某些比較次要的 JavaScript 程式(例如作用在網頁底端的程式),雖然沒有相依性問題,但是由於它不需要在網頁一開始顯示時就急著執行,放在最後也不影響的話,就可以直接使用 defer,這樣對於整個網頁的效能會更好。
在以 WordPress 架設的網站中通常都會有許多外掛模組(plugin)所提供的 JavaScript 檔,這些檔案都散佈在不同的位置,而且隨時可能更動,如果要讓這些 JavaScript 加上 async 或 defer,必須使用 WordPress 的 add_filter 功能,靠 PHP 程式來判斷與處理,這樣就算未來外掛模組有更動時,也會很好維護。
加入 async 或 defer
若要讓 WordPress 網站內所有的 JavaScript 引入檔都自動加入 async,可以在佈景主題(theme)中的 function.php 檔中,加入類似這樣的 filter:
# 把所有引入的 JavaScript 檔加入 async 屬性
function js_async_attr($tag){
return str_replace( ' src', ' async="async" src', $tag );
}
add_filter( 'script_loader_tag', 'js_async_attr', 10 );
這是將所有 JavaScript 引入檔都加入 defer 的版本:
# 把所有引入的 JavaScript 檔加入 defer 屬性
function js_defer_attr($tag){
return str_replace( ' src', ' defer="defer" src', $tag );
}
add_filter( 'script_loader_tag', 'js_defer_attr', 10 );
排除某些 JavaScript
如果想要所有的 JavaScript 引入檔都自動加入 async,但是排除某些少數的 JavaScript 檔案,就可以使用這樣的方式。
# 把所有引入的 JavaScript 檔加入 async 屬性,
# 但排除某些 JavaScript 檔
function js_async_attr($tag){
# 排除的 JavaScript 檔
$scripts_to_exclude = array(
'script-name1.js',
'script-name2.js',
'script-name3.js');
foreach($scripts_to_exclude as $exclude_script){
if (true == strpos($tag, $exclude_script))
return $tag;
}
return str_replace( ' src', ' async="async" src', $tag );
}
add_filter( 'script_loader_tag', 'js_async_attr', 10 );
其中 $scripts_to_exclude 就是要排除的 JavaScript 檔案列表。由於我們這裡是使用 PHP 的 strpos 函數來比對 JavaScript 檔案的,所以不見得一定要指定整個 JavaScript 全名,也可以使用重點的關鍵字,例如若要排除 foo-bar-core.js 與 foo-bar-libs.js 兩個 JavaScript 檔,可以直接指定 foo-bar- 這樣的關鍵字即可。
若要加入 defer 的話,就把上面這段程式碼的 async 改為 defer 即可。
限定 JavaScript 檔
如果要對每一個 JavaScript 引入檔個別指定要是否要加入 async 或 defer 的話,就可以使用這樣的方式,這種做法可以對網站進行比較細部的校調。
# 把指定的 JavaScript 檔加入 async 或 defer 屬性
function defer_js_async($tag){
# 要加入 defer 屬性的 JavaScript 檔
$scripts_to_defer = array(
'script-name1.js',
'script-name2.js',
'script-name3.js');
# 要加入 async 屬性的 JavaScript 檔
$scripts_to_async = array(
'script-name4.js',
'script-name5.js',
'script-name6.js');
# 處理 defer
foreach($scripts_to_defer as $defer_script){
if(true == strpos($tag, $defer_script ) )
return str_replace( ' src', ' defer="defer" src', $tag );
}
# 處理 async
foreach($scripts_to_async as $async_script){
if(true == strpos($tag, $async_script ) )
return str_replace( ' src', ' async="async" src', $tag );
}
return $tag;
}
add_filter( 'script_loader_tag', 'defer_js_async', 10 );
其中 $scripts_to_defer 與 $scripts_to_async 分別是要加入 defer 與 async 的 JavaScript 引入檔清單,這裡同樣可以使用重點關鍵字的方式來指定 JavaScript 檔案。
以上就是在 WordPress 中調整 JavaScript 引入檔載入的方法,善用這些技巧就可以有效提升網頁的效率,除此之外,我們還可以利用 YUI Compressor 或 Google Closure Compiler 來壓縮 JavaScript 檔案,讓 JavaScript 的載入速度更快。
