新聞資訊

[轉載]雅虎35條優化黃金守則(二)

13、Gzip壓縮文件内容 
  網絡傳輸中的(de)HTTP請求和(hé / huò)應答時(shí)間可以(yǐ)通過前端機制得到(dào)顯著改善。的(de)确,終端用戶的(de)帶寬、互聯網提供者、與對等交換點的(de)靠近程度等都不(bù)是(shì)網站開發者所能 決定的(de)。但是(shì)還有其他(tā)因素影響着響應時(shí)間。通過減小HTTP響應的(de)大(dà)小可以(yǐ)節省HTTP響應時(shí)間。
  從HTTP/1.1開始,web客戶端都默認支持HTTP請求中有Accept-Encoding文件頭的(de)壓縮格式:   
      Accept-Encoding: gzip, deflate 
  如果web服務器在(zài)請求的(de)文件頭中檢測到(dào)上(shàng)面的(de)代碼,就(jiù)會以(yǐ)客戶端列出(chū)的(de)方式壓縮響應内容。Web服務器把壓縮方式通過響應文件頭中的(de)Content- Encoding來(lái)返回給浏覽器。
      Content-Encoding: gzip 
  Gzip是(shì)目前最流行也(yě)是(shì)最有效的(de)壓縮方式。這(zhè)是(shì)由GNU項目開發并通過RFC 1952來(lái)标準化的(de)。另外僅有的(de)一(yī / yì /yí)個(gè)壓縮格式是(shì)deflate,但是(shì)它的(de)使用範圍有限效果也(yě)稍稍遜色。
  Gzip大(dà)概可以(yǐ)減少70%的(de)響應規模。目前大(dà)約有90%通過浏覽器傳輸的(de)互聯網交換支持gzip格式。如果你使用的(de)是(shì)Apache,gzip模塊配置和(hé / huò) 你的(de)版本有關:Apache 1.3使用mod_zip,而(ér)Apache 2.x使用moflate。
  浏覽器和(hé / huò)代理都會存在(zài)這(zhè)樣的(de)問題:浏覽器期望收到(dào)的(de)和(hé / huò)實際接收到(dào)的(de)内容會存在(zài)不(bù)匹配的(de)現象。幸好,這(zhè)種特殊情況随着舊式浏覽器使用量的(de)減少在(zài)減少。 Apache模塊會通過自動添加适當的(de)Vary響應文件頭來(lái)避免這(zhè)種狀況的(de)出(chū)現。
  服務器根據文件類型來(lái)選擇需要(yào / yāo)進行gzip壓縮的(de)文件,但是(shì)這(zhè)過于(yú)限制了(le/liǎo)可壓縮的(de)文件。大(dà)多數web服務器會壓縮HTML文檔。對腳本和(hé / huò)樣式表進行壓縮同 樣也(yě)是(shì)值得做的(de)事情,但是(shì)很多web服務器都沒有這(zhè)個(gè)功能。實際上(shàng),壓縮任何一(yī / yì /yí)個(gè)文本類型的(de)響應,包括XML和(hé / huò)JSON,都值得的(de)。圖像和(hé / huò)PDF文件由于(yú) 已經壓縮過了(le/liǎo)所以(yǐ)不(bù)能再進行gzip壓縮。如果試圖gizp壓縮這(zhè)些文件的(de)話不(bù)但會浪費CPU資源還會增加文件的(de)大(dà)小。 
   Gzip壓縮所有可能的(de)文件類型是(shì)減少文件體積增加用戶體驗的(de)簡單方法。


14、配置ETag 
  Entity tags(ETags)(實體标簽)是(shì)web服務器和(hé / huò)浏覽器用于(yú)判斷浏覽器緩存中的(de)内容和(hé / huò)服務器中的(de)原始内容是(shì)否匹配的(de)一(yī / yì /yí)種機制(“實體”就(jiù)是(shì)所說(shuō)的(de)“内 容”,包括圖片、腳本、樣式表等)。增加ETag爲(wéi / wèi)實體的(de)驗證提供了(le/liǎo)一(yī / yì /yí)個(gè)比使用“last-modified date(上(shàng)次編輯時(shí)間)”更加靈活的(de)機制。Etag是(shì)一(yī / yì /yí)個(gè)識别内容版本号的(de)唯一(yī / yì /yí)字符串。唯一(yī / yì /yí)的(de)格式限制就(jiù)是(shì)它必須包含在(zài)雙引号内。原始服務器通過含有 ETag文件頭的(de)響應指定頁面内容的(de)ETag。 
      HTTP/1.1 200 OK
      Last-Modified: Tue, 12 Dec 2006 03:03:59 GMT
      ETag: "10c24bc-4ab-457e1c1f"
      Content-Length: 12195
  稍後,如果浏覽器要(yào / yāo)驗證一(yī / yì /yí)個(gè)文件,它會使用If-None-Match文件頭來(lái)把ETag傳回給原始服務器。在(zài)這(zhè)個(gè)例子(zǐ)中,如果ETag匹配,就(jiù)會返回一(yī / yì /yí) 個(gè)304狀态碼,這(zhè)就(jiù)節省了(le/liǎo)12195字節的(de)響應。      GET /i/yahoo.gif HTTP/1.1
      Host: us.yimg.com
      If-Modified-Since: Tue, 12 Dec 2006 03:03:59 GMT
      If-None-Match: "10c24bc-4ab-457e1c1f"
      HTTP/1.1 304 Not Modified
  ETag的(de)問題在(zài)于(yú),它是(shì)根據可以(yǐ)辨别網站所在(zài)的(de)服務器的(de)具有唯一(yī / yì /yí)性的(de)屬性來(lái)生成的(de)。當浏覽器從一(yī / yì /yí)台服務器上(shàng)獲得頁面内容後到(dào)另外一(yī / yì /yí)台服務器上(shàng)進行驗證時(shí) ETag就(jiù)會不(bù)匹配,這(zhè)種情況對于(yú)使用服務器組和(hé / huò)處理請求的(de)網站來(lái)說(shuō)是(shì)非常常見的(de)。默認情況下,Apache和(hé / huò)IIS都會把數據嵌入ETag中,這(zhè)會顯著 減少多服務器間的(de)文件驗證沖突。
   Apache 1.3和(hé / huò)2.x中的(de)ETag格式爲(wéi / wèi)inode-size-timestamp。即使某個(gè)文件在(zài)不(bù)同的(de)服務器上(shàng)會處于(yú)相同的(de)目錄下,文件大(dà)小、權限、時(shí)間戳 等都完全相同,但是(shì)在(zài)不(bù)同服務器上(shàng)他(tā)們的(de)内碼也(yě)是(shì)不(bù)同的(de)。 
  IIS 5.0和(hé / huò)IIS 6.0處理ETag的(de)機制相似。IIS中的(de)ETag格式爲(wéi / wèi)Filetimestamp:ChangeNumber。用ChangeNumber來(lái)跟蹤 IIS配置的(de)改變。網站所用的(de)不(bù)同IIS服務器間ChangeNumber也(yě)不(bù)相同。不(bù)同的(de)服務器上(shàng)的(de)Apache和(hé / huò)IIS即使對于(yú)完全相同的(de)内容産生的(de) ETag在(zài)也(yě)不(bù)相同,用戶并不(bù)會接收到(dào)一(yī / yì /yí)個(gè)小而(ér)快的(de)304響應;相反他(tā)們會接收一(yī / yì /yí)個(gè)正常的(de)200響應并下載全部内容。如果你的(de)網站隻放在(zài)一(yī / yì /yí)台服務器上(shàng),就(jiù) 不(bù)會存在(zài)這(zhè)個(gè)問題。但是(shì)如果你的(de)網站是(shì)架設在(zài)多個(gè)服務器上(shàng),并且使用Apache和(hé / huò) IIS産生默認的(de)ETag配置,你的(de)用戶獲得頁面就(jiù)會相對慢一(yī / yì /yí)點,服務器會傳輸更多的(de)内容,占用更多的(de)帶寬,代理也(yě)不(bù)會有效地(dì / de)緩存你的(de)網站内容。即使你的(de) 内容擁有Expires文件頭,無論用戶什麽時(shí)候點擊“刷新”或者“重載”按鈕都會發送相應的(de)GET請求。
   如果你沒有使用ETag提供的(de)靈活的(de)驗證模式,那麽幹脆把所有的(de)ETag都去掉會更好。Last-Modified文件頭驗證是(shì)基于(yú)内容的(de)時(shí)間戳的(de)。去掉 ETag文件頭會減少響應和(hé / huò)下次請求中文件的(de)大(dà)小。微軟的(de)這(zhè)篇支持文稿講述了(le/liǎo)如何去掉ETag。在(zài)Apache中,隻需要(yào / yāo)在(zài)配置文件中簡單添加下面一(yī / yì /yí)行代 碼就(jiù)可以(yǐ)了(le/liǎo):
      FileETag none


15、盡早刷新輸出(chū)緩沖 
  當用戶請求一(yī / yì /yí)個(gè)頁面時(shí),無論如何都會花費200到(dào)500毫秒用于(yú)後台組織HTML文件。在(zài)這(zhè)期間,浏覽器會一(yī / yì /yí)直空閑等待數據返回。在(zài)PHP中,你可以(yǐ)使用 flush()方法,它允許你把已經編譯的(de)好的(de)部分HTML響應文件先發送給浏覽器,這(zhè)時(shí)浏覽器就(jiù)會可以(yǐ)下載文件中的(de)内容(腳本等)而(ér)後台同時(shí)處理剩餘的(de) HTML頁面。這(zhè)樣做的(de)效果會在(zài)後台煩惱或者前台較空閑時(shí)更加明顯。
  輸出(chū)緩沖應用最好的(de)一(yī / yì /yí)個(gè)地(dì / de)方就(jiù)是(shì)緊跟在(zài)<head />之(zhī)後,因爲(wéi / wèi)HTML的(de)頭部分容易生成而(ér)且頭部往往包含CSS和(hé / huò)JavaScript文件,這(zhè)樣浏覽器就(jiù)可以(yǐ)在(zài)後台編譯剩餘HTML的(de)同時(shí)并行下 載它們。 例子(zǐ):

      ... <!-- css, js -->
          </head>
          <?php flush(); ?>
          <body>
      ... <!-- content -->

爲(wéi / wèi)了(le/liǎo)證明使用這(zhè)項技術的(de)好處,Yahoo!搜索率先研究并完成了(le/liǎo)用戶測試。


16、使用GET來(lái)完成AJAX請求 
  Yahoo!Mail團隊發現,當使用XMLHttpRequest時(shí),浏覽器中的(de)POST方法是(shì)一(yī / yì /yí)個(gè)“兩步走”的(de)過程:首先發送文件頭,然後才發送數 據。因此使用GET最爲(wéi / wèi)恰當,因爲(wéi / wèi)它隻需發送一(yī / yì /yí)個(gè)TCP包(除非你有很多cookie)。IE中URL的(de)最大(dà)長度爲(wéi / wèi)2K,因此如果你要(yào / yāo)發送一(yī / yì /yí)個(gè)超過2K的(de) 數據時(shí)就(jiù)不(bù)能使用GET了(le/liǎo)。
  一(yī / yì /yí)個(gè)有趣的(de)不(bù)同就(jiù)是(shì)POST并不(bù)像GET那樣實際發送數據。根據HTTP規範,GET意味着“獲取”數據,因此當你僅僅獲取數據時(shí)使用GET更加有意義 (從語意上(shàng)講也(yě)是(shì)如此),相反,發送并在(zài)服務端保存數據時(shí)使用POST。


除此之(zhī)外,JavaScript和(hé / huò)CSS也(yě)是(shì)我們頁面中經常用到(dào)的(de)内容,對它們的(de)優化也(yě)提高網站性能的(de)重要(yào / yāo)方面:


35、避免空的(de)圖像來(lái)源

一(yī / yì /yí)個(gè)src屬性爲(wéi / wèi)空串的(de)圖像有兩種情況:

1. 直接的(de)HTML

<img src="">

2. JavaScript

var img = new Image();
img.src = "";


這(zhè)兩種情況都會引起同樣的(de)效果:浏覽器會再次向你的(de)服務器發出(chū)請求。

  • Internet Explorer 将向這(zhè)個(gè)頁面所在(zài)的(de)目錄發出(chū)一(yī / yì /yí)個(gè)請求
  • Safari and Chrome 将發出(chū)對這(zhè)個(gè)頁面的(de)一(yī / yì /yí)個(gè)請求。
  • Firefox 3 和(hé / huò)更早的(de)版本所采取的(de)動作和(hé / huò)Safari and Chrome一(yī / yì /yí)樣,但是(shì) 3.5版本 addressed this issue[bug 444931] and no longer sends a request.
  • Opera 不(bù)進行任何操作。

這(zhè)個(gè)行爲(wéi / wèi)爲(wéi / wèi)何是(shì)不(bù)好的(de)?

1、 發送大(dà)量突然的(de)請求将使你的(de)服務器宕機(Cripple your servers),尤其是(shì)每天有數百萬訪問量的(de)頁面。

2、 産生一(yī / yì /yí)個(gè)從未浏覽過的(de)頁面将浪費服務器的(de)計算周期(computing cycles)

3、 損壞用戶數據。如果你在(zài)請求中追蹤狀态(以(yǐ)cookie或是(shì)其他(tā)的(de)方式),你可能會損壞數據。即使這(zhè)個(gè)圖像請求并沒有返回一(yī / yì /yí)個(gè)圖像,所有的(de)頭被浏覽器讀取并接受,包括所有cookie。While the rest of the response is thrown away, the damage may already be done.

引起這(zhè)種行爲(wéi / wèi)的(de)根源在(zài)于(yú)浏覽器中URI的(de)解析方式。這(zhè)種行爲(wéi / wèi)定義在(zài)RFC 3986 - Uniform Resource Identifiers.當一(yī / yì /yí)個(gè)空串作爲(wéi / wèi)一(yī / yì /yí)個(gè)URI時(shí),它被認爲(wéi / wèi)一(yī / yì /yí)個(gè)相對URI(relative URI)并通過定義在(zài)section 5.2中的(de)算法被解析。這(zhè)個(gè)特例,一(yī / yì /yí)個(gè)空串,列在(zài)section 5.4當中。Firefox, Safari, and Chrome都是(shì)依據這(zhè)一(yī / yì /yí)規格來(lái)解析空串,而(ér)Internet Explorer則不(bù)正确的(de)解析這(zhè)個(gè)串,符合更早的(de)一(yī / yì /yí)個(gè)規範,RFC 2396 - Uniform Resource Identifiers (this was obsoleted by RFC 3986).所以(yǐ)技術上(shàng),浏覽器都在(zài)做它們被期望所做的(de)事情來(lái)解析relative URIs,問題是(shì)在(zài)這(zhè)個(gè)範圍,空串不(bù)是(shì)故意造成的(de)。


HTML5 adds to the description of the file:///C:/Users/Prayer/AppData/Local/Temp/msohtmlclip1/01/clip_image001.giftag's src attribute to instruct browsers not to make an additional request in section 4.8.2:

    The src attribute must be present, and must contain a valid URL referencing a non-interactive, optionally animated, image resource that is neither paged nor scripted. If the base URI of the element is the same as the document's address, then the src attribute's value must not be the empty string.

非常希望浏覽器在(zài)将來(lái)不(bù)會有這(zhè)樣的(de)問題。不(bù)幸的(de)是(shì),沒有爲(wéi / wèi)<script src=""> and <link href="">的(de)條款。或許仍需要(yào / yāo)時(shí)間來(lái)做出(chū)調整以(yǐ)保證浏覽器不(bù)會意外的(de)實現這(zhè)一(yī / yì /yí)行爲(wéi / wèi)。

這(zhè)一(yī / yì /yí)規則是(shì)受雅虎JavaScript導師Nicolas C. Zakas啓發。更新信息請參見Empty image src can destroy your site..

三、CSS部分

  • 把樣式表置于(yú)頂部
  • 避免使用CSS表達式(Expression)
  • 用<link>代替@import
  • 避免使用濾鏡

17、把樣式表置于(yú)頂部 
  在(zài)研究Yahoo!的(de)性能表現時(shí),我們發現把樣式表放到(dào)文檔的(de)<head />内部似乎會加快頁面的(de)下載速度。這(zhè)是(shì)因爲(wéi / wèi)把樣式表放到(dào)<head />内會使頁面有步驟的(de)加載顯示。
  注重性能的(de)前端服務器往往希望頁面有秩序地(dì / de)加載。同時(shí),我們也(yě)希望浏覽器把已經接收到(dào)内容盡可能顯示出(chū)來(lái)。這(zhè)對于(yú)擁有較多内容的(de)頁面和(hé / huò)網速較慢的(de)用戶來(lái)說(shuō) 特别重要(yào / yāo)。向用戶返回可視化的(de)反饋,比如進程指針,已經有了(le/liǎo)較好的(de)研究并形成了(le/liǎo)正式文檔。在(zài)我們的(de)研究中HTML頁面就(jiù)是(shì)進程指針。當浏覽器有序地(dì / de)加載文 件頭、導航欄、頂部的(de)logo等對于(yú)等待頁面加載的(de)用戶來(lái)說(shuō)都可以(yǐ)作爲(wéi / wèi)可視化的(de)反饋。這(zhè)從整體上(shàng)改善了(le/liǎo)用戶體驗。
  把樣式表放在(zài)文檔底部的(de)問題是(shì)在(zài)包括Internet Explorer在(zài)内的(de)很多浏覽器中這(zhè)會中止内容的(de)有序呈現。浏覽器中止呈現是(shì)爲(wéi / wèi)了(le/liǎo)避免樣式改變引起的(de)頁面元素重繪。用戶不(bù)得不(bù)面對一(yī / yì /yí)個(gè)空白頁面。
   HTML規範清楚指出(chū)樣式表要(yào / yāo)放包含在(zài)頁面的(de)<head />區域内:“和(hé / huò)<a />不(bù)同,<link />隻能出(chū)現在(zài)文檔的(de)<head />區域内,盡管它可以(yǐ)多次使用它”。無論是(shì)引起白屏還是(shì)出(chū)現沒有樣式化的(de)内容都不(bù)值得去嘗試。最好的(de)方案就(jiù)是(shì)按照HTML規範在(zài)文 檔<head />内加載你的(de)樣式表。


18、避免使用CSS表達式(Expression) 
  CSS表達式是(shì)動态設置CSS屬性的(de)強大(dà)(但危險)方法。Internet Explorer從第5個(gè)版本開始支持CSS表達式。下面的(de)例子(zǐ)中,使用CSS表達式可以(yǐ)實現隔一(yī / yì /yí)個(gè)小時(shí)切換一(yī / yì /yí)次背景顔色:
      background-color: expression( (new Date()).getHours()%2 ? "#B8D4FF" : "#F08A00" ); 
如上(shàng)所示,expression中使用了(le/liǎo)JavaScript表達式。CSS屬性根據JavaScript表達式的(de)計算結果來(lái)設置。expression 方法在(zài)其它浏覽器中不(bù)起作用,因此在(zài)跨浏覽器的(de)設計中單獨針對Internet Explorer設置時(shí)會比較有用。
  表達式的(de)問題就(jiù)在(zài)于(yú)它的(de)計算頻率要(yào / yāo)比我們想象的(de)多。不(bù)僅僅是(shì)在(zài)頁面顯示和(hé / huò)縮放時(shí),就(jiù)是(shì)在(zài)頁面滾動、乃至移動鼠标時(shí)都會要(yào / yāo)重新計算一(yī / yì /yí)次。給CSS表達式增加 一(yī / yì /yí)個(gè)計數器可以(yǐ)跟蹤表達式的(de)計算頻率。在(zài)頁面中随便移動鼠标都可以(yǐ)輕松達到(dào)10000次以(yǐ)上(shàng)的(de)計算量。
  一(yī / yì /yí)個(gè)減少CSS表達式計算次數的(de)方法就(jiù)是(shì)使用一(yī / yì /yí)次性的(de)表達式,它在(zài)第一(yī / yì /yí)次運行時(shí)将結果賦給指定的(de)樣式屬性,并用這(zhè)個(gè)屬性來(lái)代替CSS表達式。如果樣式屬性 必須在(zài)頁面周期内動态地(dì / de)改變,使用事件句柄來(lái)代替CSS表達式是(shì)一(yī / yì /yí)個(gè)可行辦法。如果必須使用CSS表達式,一(yī / yì /yí)定要(yào / yāo)記住它們要(yào / yāo)計算成千上(shàng)萬次并且可能會對你 頁面的(de)性能産生影響。


19、用<link>代替@import 
  前面的(de)最佳實現中提到(dào)CSS應該放置在(zài)頂端以(yǐ)利于(yú)有序加載呈現。
  在(zài)IE中,頁面底部@import和(hé / huò)使用<link>作用是(shì)一(yī / yì /yí)樣的(de),因此最好不(bù)要(yào / yāo)使用它。


20、避免使用濾鏡 
  IE獨有屬性AlphaImageLoader用于(yú)修正7.0以(yǐ)下版本中顯示PNG圖片的(de)半透明效果。這(zhè)個(gè)濾鏡的(de)問題在(zài)于(yú)浏覽器加載圖片時(shí)它會終止内容的(de) 呈現并且凍結浏覽器。在(zài)每一(yī / yì /yí)個(gè)元素(不(bù)僅僅是(shì)圖片)它都會運算一(yī / yì /yí)次,增加了(le/liǎo)内存開支,因此它的(de)問題是(shì)多方面的(de)。
  完全避免使用AlphaImageLoader的(de)最好方法就(jiù)是(shì)使用PNG8格式來(lái)代替,這(zhè)種格式能在(zài)IE中很好地(dì / de)工作。如果你确實需要(yào / yāo)使用 AlphaImageLoader,請使用下劃線_filter又使之(zhī)對IE7以(yǐ)上(shàng)版本的(de)用戶無效。


四、 JavaScript部分

  • 把腳本置于(yú)頁面底部
  • 使用外部JavaScript和(hé / huò)CSS
  • 削減JavaScript和(hé / huò)CSS
  • 剔除重複腳本
  • 減少DOM訪問
  • 開發智能事件處理程序

21、把腳本置于(yú)頁面底部 
  腳本帶來(lái)的(de)問題就(jiù)是(shì)它阻止了(le/liǎo)頁面的(de)平行下載。HTTP/1.1 規範建議,浏覽器每個(gè)主機名的(de)并行下載内容不(bù)超過兩個(gè)。如果你的(de)圖片放在(zài)多個(gè)主機名上(shàng),你可以(yǐ)在(zài)每個(gè)并行下載中同時(shí)下載2個(gè)以(yǐ)上(shàng)的(de)文件。但是(shì)當下載腳本 時(shí),浏覽器就(jiù)不(bù)會同時(shí)下載其它文件了(le/liǎo),即便是(shì)主機名不(bù)相同。
  在(zài)某些情況下把腳本移到(dào)頁面底部可能不(bù)太容易。比如說(shuō),如果腳本中使用了(le/liǎo)document.write來(lái)插入頁面内容,它就(jiù)不(bù)能被往下移動了(le/liǎo)。這(zhè)裏可能還 會有作用域的(de)問題。很多情況下,都會遇到(dào)這(zhè)方面的(de)問題。
  一(yī / yì /yí)個(gè)經常用到(dào)的(de)替代方法就(jiù)是(shì)使用延遲腳本。DEFER屬性表明腳本中沒有包含document.write,它告訴浏覽器繼續顯示。不(bù)幸的(de) 是(shì),Firefox并不(bù)支持DEFER屬性。在(zài)Internet Explorer中,腳本可能會被延遲但效果也(yě)不(bù)會像我們所期望的(de)那樣。如果腳本可以(yǐ)被延遲,那麽它就(jiù)可以(yǐ)移到(dào)頁面的(de)底部。這(zhè)會讓你的(de)頁面加載的(de)快一(yī / yì /yí)點。


22、使用外部JavaScript和(hé / huò)CSS 
  很多性能規則都是(shì)關于(yú)如何處理外部文件的(de)。但是(shì),在(zài)你采取這(zhè)些措施前你可能會問到(dào)一(yī / yì /yí)個(gè)更基本的(de)問題:JavaScript和(hé / huò)CSS是(shì)應該放在(zài)外部文件中呢 還是(shì)把它們放在(zài)頁面本身之(zhī)内呢?
  在(zài)實際應用中使用外部文件可以(yǐ)提高頁面速度,因爲(wéi / wèi)JavaScript和(hé / huò)CSS文件都能在(zài)浏覽器中産生緩存。内置在(zài)HTML文檔中的(de)JavaScript 和(hé / huò)CSS則會在(zài)每次請求中随HTML文檔重新下載。這(zhè)雖然減少了(le/liǎo)HTTP請求的(de)次數,卻增加了(le/liǎo)HTML文檔的(de)大(dà)小。從另一(yī / yì /yí)方面來(lái)說(shuō),如果外部文件中的(de) JavaScript和(hé / huò)CSS被浏覽器緩存,在(zài)沒有增加HTTP請求次數的(de)同時(shí)可以(yǐ)減少HTML文檔的(de)大(dà)小。
  關鍵問題是(shì),外部JavaScript和(hé / huò)CSS文件緩存的(de)頻率和(hé / huò)請求HTML文檔的(de)次數有關。雖然有一(yī / yì /yí)定的(de)難度,但是(shì)仍然有一(yī / yì /yí)些指标可以(yǐ)一(yī / yì /yí)測量它。如果一(yī / yì /yí) 個(gè)會話中用戶會浏覽你網站中的(de)多個(gè)頁面,并且這(zhè)些頁面中會重複使用相同的(de)腳本和(hé / huò)樣式表,緩存外部文件就(jiù)會帶來(lái)更大(dà)的(de)益處。
  許多網站沒有功能建立這(zhè)些指标。對于(yú)這(zhè)些網站來(lái)說(shuō),最好的(de)堅決方法就(jiù)是(shì)把JavaScript和(hé / huò)CSS作爲(wéi / wèi)外部文件引用。比較适合使用内置代碼的(de)例外就(jiù)是(shì) 網站的(de)主頁,如Yahoo!主頁和(hé / huò)My Yahoo!。主頁在(zài)一(yī / yì /yí)次會話中擁有較少(可能隻有一(yī / yì /yí)次)的(de)浏覽量,你可以(yǐ)發現内置JavaScript和(hé / huò)CSS對于(yú)終端用戶來(lái)說(shuō)會加快響應時(shí) 間。
  對于(yú)擁有較大(dà)浏覽量的(de)首頁來(lái)說(shuō),有一(yī / yì /yí)種技術可以(yǐ)平衡内置代碼帶來(lái)的(de)HTTP請求減少與通過使用外部文件進行緩存帶來(lái)的(de)好處。其中一(yī / yì /yí)個(gè)就(jiù)是(shì)在(zài)首頁中内置 JavaScript和(hé / huò)CSS,但是(shì)在(zài)頁面下載完成後動态下載外部文件,在(zài)子(zǐ)頁面中使用到(dào)這(zhè)些文件時(shí),它們已經緩存到(dào)浏覽器了(le/liǎo)。


23、削減JavaScript和(hé / huò)CSS 
  精簡是(shì)指從去除代碼不(bù)必要(yào / yāo)的(de)字符減少文件大(dà)小從而(ér)節省下載時(shí)間。消減代碼時(shí),所有的(de)注釋、不(bù)需要(yào / yāo)的(de)空白字符(空格、換行、tab縮進)等都要(yào / yāo)去掉。在(zài) JavaScript中,由于(yú)需要(yào / yāo)下載的(de)文件體積變小了(le/liǎo)從而(ér)節省了(le/liǎo)響應時(shí)間。精簡JavaScript中目前用到(dào)的(de)最廣泛的(de)兩個(gè)工具是(shì)JSMin和(hé / huò)YUI Compressor。YUI Compressor還可用于(yú)精簡CSS。
  混淆是(shì)另外一(yī / yì /yí)種可用于(yú)源代碼優化的(de)方法。這(zhè)種方法要(yào / yāo)比精簡複雜一(yī / yì /yí)些并且在(zài)混淆的(de)過程更易産生問題。在(zài)對美國(guó)前10大(dà)網站的(de)調查中發現,精簡也(yě)可以(yǐ)縮小原來(lái) 代碼體積的(de)21%,而(ér)混淆可以(yǐ)達到(dào)25%。盡管混淆法可以(yǐ)更好地(dì / de)縮減代碼,但是(shì)對于(yú)JavaScript來(lái)說(shuō)精簡的(de)風險更小。
  除消減外部的(de)腳本和(hé / huò)樣式表文件外,<script>和(hé / huò)<style>代碼塊也(yě)可以(yǐ)并且應該進行消減。即使你用Gzip壓縮過腳本 和(hé / huò)樣式表,精簡這(zhè)些文件仍然可以(yǐ)節省5%以(yǐ)上(shàng)的(de)空間。由于(yú)JavaScript和(hé / huò)CSS的(de)功能和(hé / huò)體積的(de)增加,消減代碼将會獲得益處。



24、剔除重複腳本 
  在(zài)同一(yī / yì /yí)個(gè)頁面中重複引用JavaScript文件會影響頁面的(de)性能。你可能會認爲(wéi / wèi)這(zhè)種情況并不(bù)多見。對于(yú)美國(guó)前10大(dà)網站的(de)調查顯示其中有兩家存在(zài)重複引 用腳本的(de)情況。有兩種主要(yào / yāo)因素導緻一(yī / yì /yí)個(gè)腳本被重複引用的(de)奇怪現象發生:團隊規模和(hé / huò)腳本數量。如果真的(de)存在(zài)這(zhè)種情況,重複腳本會引起不(bù)必要(yào / yāo)的(de)HTTP請求和(hé / huò) 無用的(de)JavaScript運算,這(zhè)降低了(le/liǎo)網站性能。
  在(zài)Internet Explorer中會産生不(bù)必要(yào / yāo)的(de)HTTP請求,而(ér)在(zài)Firefox卻不(bù)會。在(zài)Internet Explorer中,如果一(yī / yì /yí)個(gè)腳本被引用兩次而(ér)且它又不(bù)可緩存,它就(jiù)會在(zài)頁面加載過程中産生兩次HTTP請求。即時(shí)腳本可以(yǐ)緩存,當用戶重載頁面時(shí)也(yě)會産 生額外的(de)HTTP請求。
  除增加額外的(de)HTTP請求外,多次運算腳本也(yě)會浪費時(shí)間。在(zài)Internet Explorer和(hé / huò)Firefox中不(bù)管腳本是(shì)否可緩存,它們都存在(zài)重複運算JavaScript的(de)問題。
  一(yī / yì /yí)個(gè)避免偶爾發生的(de)兩次引用同一(yī / yì /yí)腳本的(de)方法是(shì)在(zài)模闆中使用腳本管理模塊引用腳本。在(zài)HTML頁面中使用<script />标簽引用腳本的(de)最常見方法就(jiù)是(shì): 
    <script type="text/javascript" src="menu_1.0.17.js"></script> 
在(zài)PHP中可以(yǐ)通過創建名爲(wéi / wèi)insertScript的(de)方法來(lái)替代: 
     <?php insertScript("menu.js") ?> 
爲(wéi / wèi)了(le/liǎo)防止多次重複引用腳本,這(zhè)個(gè)方法中還應該使用其它機制來(lái)處理腳本,如檢查所屬目錄和(hé / huò)爲(wéi / wèi)腳本文件名中增加版本号以(yǐ)用于(yú)Expire文件頭等。


25、減少DOM訪問 
  使用JavaScript訪問DOM元素比較慢,因此爲(wéi / wèi)了(le/liǎo)獲得更多的(de)應該頁面,應該做到(dào):
緩存已經訪問過的(de)有關元素 
線下更新完節點之(zhī)後再将它們添加到(dào)文檔樹中 
避免使用JavaScript來(lái)修改頁面布局 
  有關此方面的(de)更多信息請查看Julien Lecomte在(zài)YUI專題中的(de)文章“高性能Ajax應該程序”。


26、開發智能事件處理程序 
  有時(shí)候我們會感覺到(dào)頁面反應遲鈍,這(zhè)是(shì)因爲(wéi / wèi)DOM樹元素中附加了(le/liǎo)過多的(de)事件句柄并且些事件句病被頻繁地(dì / de)觸發。這(zhè)就(jiù)是(shì)爲(wéi / wèi)什麽說(shuō)使用event delegation(事件代理)是(shì)一(yī / yì /yí)種好方法了(le/liǎo)。如果你在(zài)一(yī / yì /yí)個(gè)div中有10個(gè)按鈕,你隻需要(yào / yāo)在(zài)div上(shàng)附加一(yī / yì /yí)次事件句柄就(jiù)可以(yǐ)了(le/liǎo),而(ér)不(bù)用去爲(wéi / wèi)每一(yī / yì /yí)個(gè)按 鈕增加一(yī / yì /yí)個(gè)句柄。事件冒泡時(shí)你可以(yǐ)捕捉到(dào)事件并判斷出(chū)是(shì)哪個(gè)事件發出(chū)的(de)。
  你同樣也(yě)不(bù)用爲(wéi / wèi)了(le/liǎo)操作DOM樹而(ér)等待onload事件的(de)發生。你需要(yào / yāo)做的(de)就(jiù)是(shì)等待樹結構中你要(yào / yāo)訪問的(de)元素出(chū)現。你也(yě)不(bù)用等待所有圖像都加載完畢。
  你可能會希望用DOMContentLoaded事件來(lái)代替 事件應用程序中的(de)onAvailable方法。
  有關此方面的(de)更多信息請查看Julien Lecomte在(zài)YUI專題中的(de)文章“高性能Ajax應該程序”。


圖片和(hé / huò)Coockie也(yě)是(shì)我們網站中幾乎不(bù)可缺少組成部分,此外随着移動設備的(de)流行,對于(yú)移動應用的(de)優化也(yě)十分重要(yào / yāo)。這(zhè)主要(yào / yāo)包括:


五、Coockie部分

  • 減小Cookie體積
  • 對于(yú)頁面内容使用無coockie域名

27、減小Cookie體積 
  HTTP coockie可以(yǐ)用于(yú)權限驗證和(hé / huò)個(gè)性化身份等多種用途。coockie内的(de)有關信息是(shì)通過HTTP文件頭來(lái)在(zài)web服務器和(hé / huò)浏覽器之(zhī)間進行交流的(de)。因此 保持coockie盡可能的(de)小以(yǐ)減少用戶的(de)響應時(shí)間十分重要(yào / yāo)。
有關更多信息可以(yǐ)查看Tenni Theurer和(hé / huò)Patty Chi的(de)文章“When the Cookie Crumbles”。這(zhè)們研究中主要(yào / yāo)包括:
去除不(bù)必要(yào / yāo)的(de)coockie

使coockie體積盡量小以(yǐ)減少對用戶響應的(de)影響 
注意在(zài)适應級别的(de)域名上(shàng)設置coockie以(yǐ)便使子(zǐ)域名不(bù)受影響 
設置合理的(de)過期時(shí)間。較早地(dì / de)Expire時(shí)間和(hé / huò)不(bù)要(yào / yāo)過早去清除coockie,都會改善用戶的(de)響應時(shí)間。


28、對于(yú)頁面内容使用無coockie域名 
  當浏覽器在(zài)請求中同時(shí)請求一(yī / yì /yí)張靜态的(de)圖片和(hé / huò)發送coockie時(shí),服務器對于(yú)這(zhè)些coockie不(bù)會做任何地(dì / de)使用。因此他(tā)們隻是(shì)因爲(wéi / wèi)某些負面因素而(ér)創建的(de) 網絡傳輸。所有你應該确定對于(yú)靜态内容的(de)請求是(shì)無coockie的(de)請求。創建一(yī / yì /yí)個(gè)子(zǐ)域名并用他(tā)來(lái)存放所有靜态内容。
   如果你的(de)域名是(shì)http://www.example.org/ ,你可以(yǐ)在(zài)static.example.org上(shàng)存在(zài)靜态内容。但是(shì),如果你不(bù)是(shì)在(zài)http://www.example.org/ 上(shàng)而(ér)是(shì)在(zài)頂級域名example.org設置了(le/liǎo)coockie,那麽所有對于(yú)static.example.org的(de)請求都包含coockie。在(zài)這(zhè)種情 況下,你可以(yǐ)再重新購買一(yī / yì /yí)個(gè)新的(de)域名來(lái)存在(zài)靜态内容,并且要(yào / yāo)保持這(zhè)個(gè)域名是(shì)無coockie的(de)。Yahoo!使用的(de)是(shì)ymig.com,YouTube使 用的(de)是(shì)ytimg.com,Amazon使用的(de)是(shì)images-anazon.com等等。
  使用無coockie域名存在(zài)靜态内容的(de)另外一(yī / yì /yí)個(gè)好處就(jiù)是(shì)一(yī / yì /yí)些代理(服務器)可能會拒絕對coockie的(de)内容請求進行緩存。一(yī / yì /yí)個(gè)相關的(de)建議就(jiù)是(shì),如果你 想确定應該使用example.org還是(shì)http://www.example.org/ 作爲(wéi / wèi)你的(de)一(yī / yì /yí)主頁,你要(yào / yāo)考慮到(dào)coockie帶來(lái)的(de)影響。忽略掉www會使你除了(le/liǎo)把coockie設置到(dào)*.example.org(*是(shì)泛域名解析,代表 了(le/liǎo)所有子(zǐ)域名譯者dudo注)外沒有其它選擇,因此出(chū)于(yú)性能方面的(de)考慮最好是(shì)使用帶有www的(de)子(zǐ)域名并且在(zài)它上(shàng)面設置coockie。


六、Image 部分

  • 優化圖像
  • 優化CSS Spirite
  • 不(bù)要(yào / yāo)在(zài)HTML中縮放圖像
  • favicon.ico要(yào / yāo)小而(ér)且可緩存

29、優化圖像 
  設計人(rén)員完成對頁面的(de)設計之(zhī)後,不(bù)要(yào / yāo)急于(yú)将它們上(shàng)傳到(dào)web服務器,這(zhè)裏還需要(yào / yāo)做幾件事:
你可以(yǐ)檢查一(yī / yì /yí)下你的(de)GIF圖片中圖像顔色的(de)數量是(shì)否和(hé / huò)調色闆規格一(yī / yì /yí)緻。 使用imagemagick中下面的(de)命令行很容易檢查:
      identify -verbose image.gif 
如果你發現圖片中隻用到(dào)了(le/liǎo)4種顔色,而(ér)在(zài)調色闆的(de)中顯示的(de)256色的(de)顔色槽,那麽這(zhè)張圖片就(jiù)還有壓縮的(de)空間。 
  嘗試把GIF格式轉換成PNG格式,看看是(shì)否節省空間。大(dà)多數情況下是(shì)可以(yǐ)壓縮的(de)。由于(yú)浏覽器支持有限,設計者們往往不(bù)太樂意使用PNG格式的(de)圖片,不(bù)過 這(zhè)都是(shì)過去的(de)事情了(le/liǎo)。現在(zài)隻有一(yī / yì /yí)個(gè)問題就(jiù)是(shì)在(zài)真彩PNG格式中的(de)alpha通道(dào)半透明問題,不(bù)過同樣的(de),GIF也(yě)不(bù)是(shì)真彩格式也(yě)不(bù)支持半透明。因此GIF 能做到(dào)的(de),PNG(PNG8)同樣也(yě)能做到(dào)(除了(le/liǎo)動畫)。下面這(zhè)條簡單的(de)命令可以(yǐ) 安全地(dì / de)把GIF格式轉換爲(wéi / wèi)PNG格式:

      convert image.gif image.png

“我們要(yào / yāo)說(shuō)的(de)是(shì):給PNG一(yī / yì /yí)個(gè)施展身手的(de)機會吧!” 
在(zài)所有的(de)PNG圖片上(shàng)運行pngcrush(或者其它PNG優化工具)。例如:
      pngcrush image.png -rem alla -reduce -brute result.png 
在(zài)所有的(de)JPEG圖片上(shàng)運行jpegtran。這(zhè)個(gè)工具可以(yǐ)對圖片中的(de)出(chū)現的(de)鋸齒等做無損操作,同時(shí)它還可以(yǐ)用于(yú)優化和(hé / huò)清除圖片中的(de)注釋以(yǐ)及其它無用信息 (如EXIF信息):
      jpegtran -copy none -optimize -perfect src.jpg dest.jpg


30、優化CSS Spirite 
  在(zài)Spirite中水平排列你的(de)圖片,垂直排列會稍稍增加文件大(dà)小; 
Spirite中把顔色較近的(de)組合在(zài)一(yī / yì /yí)起可以(yǐ)降低顔色數,理想狀況是(shì)低于(yú)256色以(yǐ)便适用PNG8格式; 
  便于(yú)移動,不(bù)要(yào / yāo)在(zài)Spirite的(de)圖像中間留有較大(dà)空隙。這(zhè)雖然不(bù)大(dà)會增加文件大(dà)小但對于(yú)用戶代理來(lái)說(shuō)它需要(yào / yāo)更少的(de)内存來(lái)把圖片解壓爲(wéi / wèi)像素地(dì / de)圖。 100x100的(de)圖片爲(wéi / wèi)1萬像素,而(ér)1000x1000就(jiù)是(shì)100萬像素。


31、不(bù)要(yào / yāo)在(zài)HTML中縮放圖像 
  不(bù)要(yào / yāo)爲(wéi / wèi)了(le/liǎo)在(zài)HTML中設置長寬而(ér)使用比實際需要(yào / yāo)大(dà)的(de)圖片。如果你需要(yào / yāo):
<img width="100" height="100" src="mycat.jpg" alt="My Cat" />
那麽你的(de)圖片(mycat.jpg)就(jiù)應該是(shì)100x100像素而(ér)不(bù)是(shì)把一(yī / yì /yí)個(gè)500x500像素的(de)圖片縮小使用。


32、favicon.ico要(yào / yāo)小而(ér)且可緩存 
  favicon.ico是(shì)位于(yú)服務器根目錄下的(de)一(yī / yì /yí)個(gè)圖片文件。它是(shì)必定存在(zài)的(de),因爲(wéi / wèi)即使你不(bù)關心它是(shì)否有用,浏覽器也(yě)會對它發出(chū)請求,因此最好不(bù)要(yào / yāo)返回一(yī / yì /yí) 個(gè)404 Not Found的(de)響應。由于(yú)是(shì)在(zài)同一(yī / yì /yí)台服務器上(shàng),它每被請求一(yī / yì /yí)次coockie就(jiù)會被發送一(yī / yì /yí)次。這(zhè)個(gè)圖片文件還會影響下載順序,例如在(zài)IE中當你在(zài) onload中請求額外的(de)文件時(shí),favicon會在(zài)這(zhè)些額外内容被加載前下載。
  因此,爲(wéi / wèi)了(le/liǎo)減少favicon.ico帶來(lái)的(de)弊端,要(yào / yāo)做到(dào):
文件盡量地(dì / de)小,最好小于(yú)1K 
在(zài)适當的(de)時(shí)候(也(yě)就(jiù)是(shì)你不(bù)要(yào / yāo)打算再換favicon.ico的(de)時(shí)候,因爲(wéi / wèi)更換新文件時(shí)不(bù)能對它進行重命名)爲(wéi / wèi)它設置Expires文件頭。你可以(yǐ)很安全地(dì / de) 把Expires文件頭設置爲(wéi / wèi)未來(lái)的(de)幾個(gè)月。你可以(yǐ)通過核對當前favicon.ico的(de)上(shàng)次編輯時(shí)間來(lái)作出(chū)判斷。 
Imagemagick可以(yǐ)幫你創建小巧的(de)favicon。


七、 Mobile部分

  • 保持單個(gè)内容小于(yú)25K
  • 打包組件成複合文本

33、保持單個(gè)内容小于(yú)25K 
  這(zhè)條限制主要(yào / yāo)是(shì)因爲(wéi / wèi)iPhone不(bù)能緩存大(dà)于(yú)25K的(de)文件。注意這(zhè)裏指的(de)是(shì)解壓縮後的(de)大(dà)小。由于(yú)單純gizp壓縮可能達不(bù)要(yào / yāo)求,因此精簡文件就(jiù)顯得十分重 要(yào / yāo)。
  查看更多信息,請參閱Wayne Shea和(hé / huò)Tenni Theurer的(de)文件“Performance Research, Part 5: iPhone Cacheability - Making it Stick”。


34、避免空的(de)圖像來(lái)源