有關web前端優化的博文,博客園中有許多網友的博客中都有介紹,並且詳細、精準。樓主打算寫這個博客,算是對本身一年工做來的一個總結和積累有些知識從別的地方拷貝過來的,可是都審查過。css
引言:html
1. 慢的頁面可能會網站失去更多的用戶.
2. 慢500ms意味着20%的用戶將放棄訪問(google)
3. 慢100ms意味着1%的用戶將放棄交易(amazon)前端
經過上面列舉的三個數據,能夠看到web前端優化的重要性,而做爲程序員,總有一股矯情勁,但願將本身開發出來的東西能更加的完美。:)java
通常來講,咱們從變化性上把數據分紅兩種類型,變和不變.那麼不變的數據能夠緩存,變化的數據不能緩存,這是一個常識,也就是說要減小咱們的http請求次數這個目標能夠轉換成把數據分爲變化和不變化兩個部分.不變化的數據不須要再次請求,這樣http請求的次數就減小了,下面咱們分點來描述將數據分類的途徑.程序員
包括腳本、樣式文件和圖片,能夠有選擇的把一些Js和css能夠合併成一個文件,一些圖片可使用css sprites技術。這樣作的緣由是什麼?作過web開發的人都知道,js和css基本是不變的,是靜態文件,圖片亦然。那麼不變的文件若是適當的合併在一塊兒,會有什麼效果呢?請求的次數從屢次變成了一次,這樣http請求的次數就減小了。其實對於js的合併更是尤其重要,咱們知道瀏覽器對js的加載是阻塞式的。什麼意思呢,對於css和圖片之類的,瀏覽器大多支持並行加載,由於瀏覽器加載DOM樹時,檢測到會先預留一個節點,進而進行下面的加載,而js中存在建立DOM節點的可能,因此加載js存在一個解析的過程。web
對於靜態內容:設置文件頭過時時間Expires的值爲「Never expire」(永不過時) ajax
動態頁面,在代碼中添加cache-control,表示多少時間以後過時,如:
response.setHeader("Cache-Control", "max-age=3600");
若是使用了Expires文件頭,當頁面內容改變時就必須改變內容的文件名。一般是在文件內容後加版本號
這一點是大多數人都忽略得,以前不少人在罈子上發佈本身得小系統,還有demo,ahuaxuan跑過去一看,my god,一堆又一堆得js,css,既沒有恰當得合併,也沒有設置過時時間.每次刷新頁面都要從新下載這一堆又一堆的js,css.http請求那叫一個多啊.無謂了流量就這樣產生了.
這一點在企業應用的系統中也時有發生.好比咱們使用extjs做爲前端的技術,400多k啊,每打開一個頁面都導入,下載這個js,夠無聊的.那麼童子們可能就要問了,靜態文件爲啥不用apache,lighttpd等呢,答,用了又怎麼樣,不設expire或者max-age不是同樣要下載,最好的方法是寫一個filter,再filter中判斷,若是url知足必定的條件(好比符合配置文件中的正則表達式),那麼就設置一個max-age,這樣就ok,太簡單了,幾行代碼就能夠搞定.快哉.正則表達式
緩存的方法同動態頁面,ajax請求須要使用get方式,url長度爲2k(ie)限制(post請求有兩個過程,1發送請求headers,2發送請求數據,根據http規範,get請求只會發送一個tcp包).--------這一段話來自yahoo,先無論其真假,咱們從另一個方面來考慮一下爲何最好使用get方式,講一個ahuaxuan經歷過的事情,以前有一個項目的ajax請求使用了post方式,後來發現常常出錯,並且拋出了squid的錯誤,由於咱們的網站使用了squid,問題就出在這裏了,從http協議上能夠了解到,method=post是指把數據提交到服務器上去,那麼squid的一個特性是不會緩存post請求(事實上它確實不該該緩存,由於這樣會違反http協議中的語義),把ajax請求改爲get方式以後,一切恢復如常.apache
重複的js導入也有可能致使ie從新加載該腳本 。後端
有一種常常被網頁開發者忽略卻每每十分浪費響應時間的跳轉現象。這種現象發生在當URL本該有斜槓(/)卻被忽略掉時。這時候會返回一個301的狀態碼,而後瀏覽器從新發起一次請求.在企業應用裏,重定向是咱們在企業應用中經常使用的技術,不過用在網站項目上,您可要當心了,由於普通的重定向實際上是server在response header中設置http status=302,瀏覽器收到以後,判斷出是302,會從新發送一個請求,目標地址是前一次返回中指定的地址.在網站項目中若是能夠不用重定向就別用吧.若是您作企業應用項目,ok,關係不大,您就放心的」定」吧.
小節,減小http請求次數分爲了以上5個小點,每一個小點以後附加一些實例,你們能夠根據這些點來判斷本身的項目是否能夠有優化的地方.
使用cdn
讓內容更靠近用戶,這有啥好說呢,原理很簡單,就是根據用戶瀏覽器所在機器的ip來判斷哪些服務器離用戶最近,瀏覽器會再次去請求這些最近的機器.通常的cdn服務商是經過開發本身的dns server來達到這個目的的.不過這個是一般狀況哦,技術實力比較高,或者場景比較特殊的公司會開發本身的cdn.固然無論怎麼說,使用cdn確定可使頁面響應更快(也包括音頻,視頻,圖片,文本文件,等等等等)
Gzip壓縮全部可能的文件類型是減小文件體積增長用戶體驗的簡單方法。好比原本400k的文件,壓縮一下以後只有50k-100k,那麼網絡的流量就馬上下來了,壓縮的代價是服務器端要壓縮文件,須要消耗cpu,瀏覽器須要解壓文件,也須要消耗cpu,不過對於現代這麼nb的pc,來講,瀏覽器解壓一下數據帶來的cpu消耗簡直不值一提.因此您就壓吧.不過壓的時候要當心哦,有的瀏覽器在特定場景下會出去一些小bug,致使頁面不正常.好比ie6在跨域的時候可能會有些小麻煩,把這部分數據的gzip去掉就能夠了.
壓縮js可使用JSMin或者YUICompressor,後者同時能夠壓縮css,這個也沒啥好說的,照作吧.有關YUI Compressor 這個,能夠了解下,樓主試用過,不錯。
其實這一點也能夠當作是區分不變數據和變化數據.不少人喜歡在頁面上寫不少不少的js和css,這些數據其實都是不會變化的數據,也就是說這些數據也是能夠緩存在瀏覽器上的,經過把它們獨立成外部文件,能夠把這些數據緩存起來.這樣作看上去是增長的請求的次數,可是因爲第一次請求以後該部分數據已經被緩存,因此第二次就無需再請求後端,減小了網絡帶寬的開銷.
cookie是用於身份認證尤爲是個性化等操做,它是在http的請求頭中進行交換的,它體積越大,則響應越慢;
每3000字節的cookie在DSL的帶寬中會增長80毫秒的響應;因此除去沒必要要的cookie,已經使用短小的文件名和儘量小的減小cookie的大小都有利於改善響應時間。
因爲二級域名能夠拿到一級域名得cookie,那麼若是,而二級域名之間確不能相互共享cookie,因此合理得設置cookie得域名也能夠避免無必要得帶寬浪費和響應速度得增長.
該過時就過時,不要讓沒必要要的數據一直帶在身上走來走去.
爲圖片或者其餘靜態資源文件使用子域或者創建新的獨立域名(申請新的域名),避免無必要的cookie傳輸,固然也是要在有必要得狀況下,圖片類網站確定有必要,javaeye上得圖片並無使用域分離,因此咱們得cookie其實會帶到罈子得圖片服務器上去,每次請求圖片都是如此(不過還好,罈子裏沒有什麼圖片,因此這方面的浪費不大).
小結,其實cookie上的問題,單次請求看上去也不是什麼大問題,好像是無所謂得事情,就那麼幾十個byte,至於嗎,不過你們都據說過水滴石穿,繩鋸木斷的故事.因此該作的,咱們仍是要作,正所謂,勿以善小而不爲,勿以惡小而爲之.
把樣式表放在文檔底部的問題是在包括Internet Explorer在內的不少瀏覽器中這會停止內容的有序呈現。瀏覽器停止呈現是爲了不樣式改變引發的頁面元素重繪。用戶不得不面對一個空白頁面。
HTML規範清 楚指出樣式表要放包含在頁面的<head />區域內:「和<a />不一樣,<link />只能出如今文檔的<head />區域內,儘管它能夠屢次使用它」。不管是引發白屏仍是出現沒有樣式化的內容都不值得去嘗試。最好的方案就是按照HTML規範在文 檔<head />內加載你的樣式表。
腳本帶來的問題就是它阻止了頁面的平行下載。HTTP/1.1 規範建議,瀏覽器每一個主機名的並行下載內容不超過兩個。若是你的圖片放在多個主機名上,你能夠在每一個並行下載中同時下載2個以上的文件。可是當下載腳本時,瀏覽器就不會同時下載其它文件了,即使是主機名不相同。
Js放在底部加載其實並不影響瀏覽器展現頁面,除非用戶會在js加載完成以前就調用某個js方法,好比說頁面剛展示到一半,可是剛好這一半里有一部分是調用了還未下載的js,這個時候就會出問題了,若是童子們遇到這種狀況,能夠把這部分js先加載.
若是能夠的話,將這些CSS和js都緩存在本地瀏覽器中,由於這些均可以考慮爲靜態文件。
咱們在不少地方用js輸出一段html片斷時一般會使用以下代碼:
var _html = ""; _html = "<div style='padding-bottom: 5px'>"; _html += "<span class='icon_favorite' style='padding-top: 2px; padding-bottom: 2px'>這是js打印出來的</span>"; document.write(_html);
下面看看用join如何書寫:
var _html = []; var i = 0; _html[i++] = "<div style='padding-bottom: 5px'>"; _html[i++] = "<span class='icon_favorite' style='padding-top: 2px; padding-bottom: 2px'>這是js打印出來的</span>"; document.write(_html.join(""));
或者使用push:
var _html = [];
_html.push("<div style='padding-bottom: 5px'>"); _html.push("<span class='icon_favorite' style='padding-top: 2px; padding-bottom: 2px'>這是js打印出來的</span>"); document.write(_html.join(""));
樓主看web性能指南中有提到,這種寫法更高效。
低效率:
//效率低的 function GetDivNum() { var divs = document.getElementsByTagName("div"); var start = new Date().getTime(); for (var i = 0; i < divs.length; i++) { //"效率低" } var end = new Date().getTime(); alert("用時:" + (end - start) + "毫秒"); }
高效率:
//效率高的 function GetDivLen() { var divs = document.getElementsByTagName("div"); var start = new Date().getTime(); for (var i = 0, len = divs.length; i < len; i++) { //"效率高" } var end = new Date().getTime(); alert("用時:" + (end - start) + "毫秒"); }
緣由:
主要是由於for循環在執行中,第一種狀況會每次都計算一下長度,而第二種狀況倒是在開始的時候計算長度,並把其保存到一個變量中,因此其執行效率要高點,因此在咱們使用for循環的時候,特別是須要計算長度的狀況,咱們應該開始將其保存到一個變量中。可是並非只要是取長度都會出現如此明顯的差異,若是咱們僅僅是操做一個數組,取得的是一個數組的長度,那麼其實兩種方式的寫法都差很少。這裏再也不測試了。
OK,先總結道這裏,下篇介紹前端優化結合後臺的一些操做,主要簡介如何實現js的合併以及壓縮輸出。