2008-07-16

優化網站內的 Javascript

時代不一樣了,老早在寫「網頁程式」的時候,瀏覽器端只要 Parse 單純的 HTML(或下載顯示圖片),資料的處理,都由瀏覽器透過 POST/GET 方法和伺服器發出需求,伺服器處理完畢做完回應給瀏覽器才算完成。現在的網站服務大量套用 AJAX 和 Javascript,很多處理在 Client(瀏覽器)端就能先做,就算丟給伺服器處理也可以「非同步」完成,帶來的好處除了伺服器的負擔變輕、瀏覽器這邊也能夠有更快的反應速度(也可以搞一些畫面效果)。但也因為越來越多的 Javascript 被使用,即使是非同步在執行,應該也會發現處理的 Loading 被分擔到使用者端的瀏覽器上,這也是為什麼連到所謂「Web 2.0」相關的服務和網站時,查看自己的 CPU Loading,常常導致滿載的程式都是瀏覽器,使用效能差一點的電腦,連這類網站常常 Lag 到不行。我想每個架站、寫 Blog 或提供網路服務的人,應該都希望使用者或讀者在連線瀏覽時,不會有「連上你的網站要等很久」的感覺,除了網路頻寬外,如何優化網站程式碼也是一個重要的課題。除了增加伺服器端的處理效率(調整硬體或資料庫),交付給使用者執行的 Javascript 程式,或許也是增加效能的關鍵。

檢視使用的程式碼(Code Review)

我想看我 Blog、參考那些 Blogger Hack 的人會發現,首先,我會避免用外部 Include 進樣板範本的 Javascript 檔(像這類語法:<script type="text/javascript" src="xxx.js"></script>),因為一旦你外部引用的檔案掛了,等同於瀏覽器不能執行該 Javascript 的相關功能,利用該 Javascript 去實現操作介面或網頁模組全不能動,那連帶的衝擊有多大可想而知(當然,如果你網頁和引用的 Javascript 可以放在同一台機器上,同生死共患難,那反倒建議儘量用引用的比較好管理)。其次,我很多 Hack 其實也是參考人家的,但,我會「取其精華」、只保留該功能用得到的變數和函式,這樣做主要是簡化程式碼、減少載入時間,另一方面也讓自己能掌握每個函式的到底在幹嘛,能夠進一步優化和改寫(尤其很多特定功能的 Javascript,裡面殘留作者「懶得刪除」的無用程式碼,自己看了很礙眼)。不過由於 Script 的結構容忍度高(鬆散不嚴謹),不像要 Compile 的程式語言在 Build 的時候會做檢查,自己寫的時候也都只做到「能跑就好」,因此很多地方可能效率太差、沒測試到就會發生 Bug。後來看到 Will 的一篇文章:驗證你的 JavaScript 程式:JSLint,該文提到一個線上驗證 Javascript 程式的服務:JSLint,它會用嚴謹的標準去檢驗自己寫 Javascript,像是短少分號啦、變數沒有宣告之類的,小地方可以糾正自己不良的習慣,進而減少 Javascript 在客戶端出錯的機會,認為寫程式是一門「藝術」的人一定要參考看看。

程式壓縮瘦身

如果這個外掛的 .js 是自己能掌握的(就是放在自己的空間),或許可以先「壓縮」,經過「瘦身」以後放上網路,這樣檔案會變小,使用者下載讀取的速度也會變快。參考了這篇文章:「上線前用 JSMin 壓縮你的 JavaScript 檔案」中提到的 JSMin,還有線上的壓縮工具 Packer,以及很多 Javascript Library 愛用的 Javascript Compressor,這些都可以讓你自己外掛或自行撰寫的 Javascript 達到壓縮的效果(減少不必要的字元),檔案變小、程式碼變少自然載入就會變快,這樣也是一種優化的好辦法。

找出瓶頸、調整位置延緩執行

好吧,對不會改寫 Javascript、或迫不得已一定要引用別的外部 .js 檔的人來說,難道沒有優化的辦法嗎?有!在重灌狂人這篇文章提到,有個 Firefox 用的套件:Firebug 可以幫網頁測速度,抓出拖慢網站的元兇,如果自己網站用了一堆外掛 Widget,這是一個可以找出拖累網站瀏覽速度元兇的好辦法。那,找到元兇該怎麼辦呢?最簡單的方法就是不要用了(..XD),要不,就是把該功能儘量移到程式碼下方或後面,至少前面的部份能夠先順利顯示出來(AJAX 的好處)。那,如果該段程式碼就是要在前面、不能改動位置,還有一招,可以在 JavaScript 的宣告標籤裡加上 defer 屬性(一樣是從 Will 的文章,這篇:「不要讓 JavaScript 拉長你網站的反應時間 」學來的),例如:

<script type="text/javascript" src="xxx.js" defer="defer"></script>

不過以上各種優化的招式,請先確定真的知道自己在做什麼(那種什麼程式都不懂的小朋友不要學,叔叔有練過,這有危險性,不知道亂套用只會讓你的網站掛掉),而我檢視自己的 Blog,其實能夠調整的地方並不多(一方面有優化過了,另一方面我不用 include JS 的語法,都用 inline 的 Javascript,無從調整起),不過還有個地方可以玩,就拿來當作範例:我網站裡有裝 Google Analytics、一項 Google 提供用來分析流量的站長工具,沒辦法,它就要我一定要放一段 Code 才能啟用該項功能,所以套用以上提到的 defer 屬性,變成這樣:

<!-- Used for Google Analytics  -->
<script src='http://www.google-analytics.com/urchin.js' type='text/javascript' defer="defer"/>

放的位置不變,照理來說該 Script 會比較慢執行才是。接下來是 Google Analytics 會呼叫的函式 (就是有呼叫 urchinTracker 函式的那一段),本來人家是要擺在 <body> 的後面,我給它搬到 </body> 的前面,這樣就算是「最後執行」了。這個 Google Analytics 的範例用了幾個優化網站瀏覽的技巧,而且(應該)不會影響到顯示和相關功能,雖然我認為自己 Blog 的顯示效率已經一些搞一堆外掛的 Blog 好一些,但有時候還是會卡卡的不大滿意,看來有機會應該對整個網站程式碼做總體檢,用以上的工具和原則檢視一番,對網頁瀏覽時的效能說不定更進一步的明顯提昇。

回應: 10

匿名 提到...

其實引用站外的 script 也是有好處的啦,例如方便安裝,易於維護就是很重要的一點!
我個人是比較傾向易於維護的方向,效率只要在可以接受的範圍內,應該都不會有太嚴重的反感,不過據我瞭解,真正會拖慢網站速度的是廣告跟flash小玩意,JS 真的只是所有效率問題中最輕微的啊。

Abin 提到...

To LVCHEN:
如果沒有連不上的疑慮,我私底下也是儘量用引用 Script 的方法。不過有一次我把 Blog 需要的 js 放在 googlepage 的空間,結果掛了(就連不上),一堆功能不能動的窘境可想而知。另外,像 LVCHEN 您也寫過不少程式,有時候您發表的功能弄成 js 檔,結果有鄉民套用在他的空間(沒有下載放自己的地方,直接外部引用您的檔案),最後搞成你的空間和頻寬在服務他人的 Blog,這樣就算了,哪天自己改版還會影響到對方的網站,人家還會來函詢問追究,這也是我碰過的狀況。
您做了很多方便安裝的 JS 功能,我也多少都有參考過,真的是方便了很多不懂程式的人,我走的就是相反路線,用手工打造、不好安裝,但可以保留自己的彈性和效能。
我知道拖慢系統最多的是 Flash、廣告或是即時播放的音樂和影片(因此我都沒放 XD),搞無可搞只好去動 Javascript 的腦筋囉~

水瓶尤加利 / Eucaly61 提到...

To Abin,
最近正在找相關資料(JS 語法檢查, 壓縮, 優化, ...), 正好你就有這篇文章
真是感謝!!

LVCHEN 提到...

其實我也是「手工」打造啦,對我來說也很不好安裝耶(苦笑)!

一開始也是自用,因為懶惰與需求,才會寫這些東西,後來想說獨樂樂不如大家一起玩得很快樂,所以就把它們做成 js 的外掛,讓大家直接拿去玩,而我大家引用的連結雖然是我的 googlepage ,但我認為那其實也是公開的空間,頻寬也是算 google 的,實在不用太計較,而且一個的檔案才7k~10k,負擔其實很小,估計除非 100000 人/天,才有可能掛掉吧!

我的原始碼是完全開放,不久後我會寫個比較詳細的wiki,方便以後有需要的人參考或進一步的開發。

其實我覺得我們做的並不是相反地路線,我認為我們只是很單純的從不同的起點開始,因為我選擇的是先讓大家方便使用,而後再利用現有的範例給後來想要一起研究的朋友一個方向,其實這一切再怎麼說也是從最為基本的東西開始,你做的一切我也曾經歷過,只是我沒有寫出來而已(畢竟這主題跟我的部落格有點無關)。

其實手攻打造,也是可以容易安裝,甚至保持修改的彈性,不知道Abin 有沒有想過這點?至少我是這麼思考,所以我的外掛不能很單純的只看 js 檔的設計而已,應該要把我在安裝上面的努力也算進去才行。

而效能嗎?呵呵,LVCHEN 也是經過幾次改版,效能應該是可以掛保證的囉!

其實害怕連結會掛,這應該是所有的網頁都害怕的惡夢,卻也是必須容忍的現實考量,其實若是有稍微研究 blooger 的範本,它預設至少就有引入兩個以上的檔案(一個 js 一個 css),若是修改過的範本,可能還會更多。當然引入外部檔案愈少愈穩定的觀點我是同意啦,用 Abin 現在的作法我也蠻喜歡的,如果再經過壓縮後放入網頁元素中,絕對會執行的更有效率!

另外我也討厭有人來追究,或是要求訂製(如某些貴站的讀者那樣),但如果是有建設性的新功能,或是能有效增加讀者與格主互動的好主意,我也會欣然接納,讓我的外掛再進化呢!

我的討論似乎有點離題,真的只是有感而發,請 Abin 勿怪啦!

Abin 提到...

To LVCHEN:
您說的很多我也有同感,只不過一開始我的 Blog 只打算當個人的「筆記」,出發點不是為了教學、分享,只是忍不住會雞婆回應,變得好像在教學,充其量只不過是相互討論求進步罷了。
我平常工作已經不寫程式了,這個空間只是無聊時過過寫程式癮的,所以就亂寫亂改,寫複雜一點還有個好處,可以減少「小白」來發問,反正都用「沒程式背景的人別用」塘塞就好,真的想用又不懂範本程式的,就推去您的 Blog 參考您的懶人安裝版就好了~呵呵~

Hans 提到...

大大您好(不好意思,若發問位置不正確,請包涵^^):

不好意思,有一個問題一直在我心中很久了,不過一直無解…

我管理了許多Blog,部分是直接套用無腦包,部分是自己改版型(一個功能一個功能加),不過後來都遇到一個問題,就是加入「表格」(table)功能時,Firefox、chrome都看得到,但是IE就看不到table裡的東西了…(完全不見)
請問有什麼地方可以調整嗎?(小弟不會寫程式,只會按著網路上的說法設定而已)

請參考 http://seed.hans543.com ,分別用IE和Firefox開,看到Blog的最下方,應該有兩本相簿才對,但是IE看不到…

(我的個人Blog是 http://hans543.com ,不過也是遇到這個問題,結果都沒辦法使用表格來編排版面…)

再請大大解惑了,感謝感謝 Orz(跪)

Abin 提到...

To 翰仔:
請你查看你自己的樣板原始碼,裡面你自己加了一句:
table {display:none;}
我相信也許你不懂程式,但英文應該也看得懂,這句話加在你的程式碼裡,會有怎麼樣的效果,請移除這一行再試試看。

Hans 提到...

感謝Abin大大!
果然可以了…(原來是在加入「移除nav bar」的Hack時,裡頭加的…)

不過移除之後,IE開啟BLOG是可以用表格了,但是…FF開啟時,卻出現了NAV BAR…Orz

看來,要去找找其他移除NAV BAR的方法了…

真的非常感謝你捏^^

水瓶尤加利 / Eucaly61 提到...

To 翰仔:
請參考 Abin 的舊文 隱藏 Navbar
我自己用的是同一篇提到的 隐藏blogger导航栏 (透明度 + 自動隱藏/顯示)

Hans 提到...

Dear 水瓶尤加利:

感謝你的分享,我已改好囉^^
(其實,加上另一行 #navbar {display:none;} ,目前連FF也看不到NAVBAR囉^^)

張貼留言

歡迎留言或發表意見,不過要理性不做人身攻擊。匿名的朋友得到回應的速度會比較慢喔~
發問相關的禮貌和規矩請先參考這篇文章,不當留言、和本文無關的回應可能會被直接刪除無視喔!