每個原始檔要先最小化,然後依照引用的順序合併。檔名可以在佈署時動態產生,常用的選擇有亂數、佈署版本的號碼或名稱、最後修改的檔案時間戳記、或可閱讀的曰期時間字串。
每個頁面所引用的JavaScript檔,組合會有很多種。所以對整個網站考量時,就有幾種合併的作法,以下是比較常用的。
整個網站用到的所有JavaScript,都合併成一個檔案
適合所有頁面引用的JavaScript,組合並不多時。並且引用的順序都一樣,也就是順序不影響的時候。這種作法當然網站速度最快,但是常常每個頁面引用的JavaScript,都有不同。而且有些JavaScript檔案,只在一、二個網頁被引用到,這個比例高的話,就變成每一頁都還要引用原本只需要在那一個網頁要讀取的JavaScript。有一些這類的JavaScript函式庫還滿大的,例如所見即所得編輯器(WYSIWYG),所以實務上不見得是最適合的作法。將所有頁面,或是超過一半的頁面,都有引用到的JavaScript,合併成一個檔案
這個JavaScript會被全部的網頁所引用,然後每個網頁再各自去合併自已的專屬JavaScript檔案。也就是變成一個是整個網站都用到的合併檔,另一個是這個網頁用到的合併檔。這樣的作法,會減少單一頁面的傳輸量,不至於包含了過多沒有用到的JavaScript檔案,但是至少會有兩次的JavaScript請求。適合每個網頁所引用的JavaScript很分歧,而且檔案又不算小的時候。這也是一般常見的情況。每一個網頁各自合併自己引用的檔案
這樣每個網頁只會有一個JavaScript請求,而且不會有多餘的內容,也容許相同組合的JavaScript以不同順序引用。缺點就是你可能需要把JavaScript合併成多種組合,最多到和網頁數一樣多。如果在各網頁間,引用相同的JavaScrip檔案數量很少時,就適合用這個作法。其實這個作法不用管理”共同的”及”各別的”JavaScript檔案,是我比較喜歡的作法。
合併完成後,再來就是要最小化(minify)。JavaScript很適合最小化,可以用語法解析器(parser)檢查,並把不需要的空白去掉。例如使用rhino、jslint。
在合併完後,尤其是最小化之後,JavaScript原始檔會變得完全不能由人去編輯,所以合併及最小化的工作必須在佈署時期,由工具幫我們作。最好是命令列的工具,可以整合進專案的自動管理流程。 如果原本的一個JavaScript檔案,被合併到多個合併後的檔案。那麼,即使你只改了原始檔的一個字,所有合併後的檔案,都要重新產生,使用者也應該重新下載。 這裡可能有二個問題:
- 我們有設定快取標頭,如何通知使用者(瀏覽器)下載新的合併檔?
- 只改一個檔案的一個字,就要使用者重新下載合併的檔案,會不會影響速度?
第一個問題,只要改變下載合併檔的URL,下次使用者到這個網頁,就會重新下載這個合併檔。麻煩的地方在於,我們要把所有修改過的合併檔,傳到伺服器上。也就是說,一定要再走一次佈署流程,把所有合併檔都產生好,再佈署上去,即使有工具幫我們作,負擔也是不小,過程也很多地方可能會出錯。所以使用「lazy initialization」,在伺服器端作「合併」、「最小化」的工作,也是一個不錯的方法。
第二個問題,我認為影響不大。因為我們的目標是,即使客戶端完全沒有快取,也要能很快的顯示網頁。以每一個網頁只使用一到兩個元素來看,負擔很小。這也可以說是,因為我們把請求數目大量的減少,所以不用太擔心快取的問題。
進行好合併、最小化之後,其它的工作就比較簡單了。也就是在網站伺服器上,對JavaScript檔案進行壓縮及設定快取標頭,把JavaScript的下載最佳化。
JavaScript檔案和區塊,都應該放在HTML文件的最後面。例如我的習慣,是像這樣子:
......
我們常常需要在我們的網站上,引用第三方的JavaScript函式庫,如社羣網站API、測量工具、或廣告商等。以前通常會對放置JavaScript的區塊作限制,甚至要求要用document.write()的語法,對我們網站的效能造成嚴重的限制。我真的不希望使用者看我的網頁,要先等廣告render好,才出現真正的內容。尤其是JavaScript的請求會擋住(block)網頁的render,如果第三方的網站回應較慢,還會連累我們的網站,讓使用者等半天,只看到白畫面。 還好,現在比較大的第三方JavaScript函式庫,都支援了非同步的JavaScript使用法。所以我們也要把這些JavaScript,在HTML文件和資源都準備好(onload)之後,再去呼叫初始化。初始化的步驟通常是用JavaScript插入一段引用第三方JavaScript函式庫的