CSI是瀏覽器端的動靜整合方案,當我文章發表後有朋友就問我,CSI技術是不是就是透過ajax來載入資料啊,我當時的回答只是說你的理解有點片面,那麼到底什麼是CSI技術了?這個其實要和動靜資源整合的角度來定義。
CSI技術其實是在頁面進行動靜分離後,將頁面載入分成兩個步驟完成,第一步是載入靜態資源,靜態資源載入完畢後進行第二步驟載入動態資源。不過這個定義還是表述的不全面,不全面的地方就是我們要強調動靜分離的目的,我們把頁面裡的動靜資源拆分出來是為了將靜態資源做有效的緩存,這個靜態資源可能是在靜態web容器上,也有可能是在CDN上,也有可能是在瀏覽器上,不管靜態資源是如何快取的,我們的目的都是為了讓靜態資源載入的速度更快,如果我們沒有讓靜態資源載入變得高效,就算我們使用了CSI的形式來設計頁面,其實也沒有發揮CSI的優點,反倒還會一不小心引入CSI的缺點。那什麼是CSI的缺點呢?具體如下:
CSI的缺點一:CSI不利於頁面的SEO即搜尋引擎最佳化。搜尋引擎的網路爬蟲一般是根據url造訪頁面,取得頁面的內容後去掉沒用的資訊例如:css樣式,js腳本,然後分析剩下的文字內容,因此假如頁面的一部分內容需要進行異步加載,那麼這個載入控制肯定是由javascript程式碼來完成的,因此網路爬蟲爬下來的頁面裡異步載入的操作是沒法執行的(聽說有些高階的爬蟲可以執行異步的操作,抓取異步的內容,即便有這個技術,大部分主流的爬蟲還是會忽略掉javascript程式碼的也會忽略非同步載入的內容的),這就會導致爬蟲爬的頁面裡有部分資訊遺失了,所以說CSI對SEO不太友善。不過這個缺點我們仔細分析下,可能不會是那麼嚴重,前面我們談論了很多靜態分離的策略,如果我們動靜分離策略做的好,那麼動態資源基本上都是不能被緩存的內容,經常發生變化的內容,這些變化的內容本來就不需要被網路爬蟲爬到,就算真的被爬到,搜尋引擎有個查詢結果指向了這個頁面,我們點開這個頁面結果也是在頁面找不到被搜尋的關鍵字,這種情形我相信很多朋友在使用搜尋引擎時候都會碰到過。不過我想如果開發人員沒有正確使用CSI,那麼這塊他們可能也不會處理的特別好,因此這個缺點還是很容易被引進的。
CSI的缺點二:我們那麼費時費力想讓自己的網站靜態化,目的就是想讓頁面加載更快點,我們簡簡單單把頁面加載分成了兩個步驟進行,那麼這麼做就真的快嗎?這可不一定啊,其實動靜分離的做法和我上一個系列裡講到的資料庫讀寫分離有類似之處,資料庫讀寫分離我們是透過拆分原表的讀寫之間的關聯關係,從而達到解決讀取的瓶頸問題,而網頁的動靜分離是因為靜態資源很容易被最佳化,所以我們要分割動靜資源。所以當我們對資源進行了動靜分離,但是又沒有優化靜態資源,這個一看就知道我們缺少一個加速頁面加載速度的操作,那麼真的能讓頁面加載快點,還真的很難說了,而且非同步載入需要執行javascript程式碼才行,但靜態資源載入時候很容易造成javascript腳本被阻塞,如果阻塞的腳本剛好是異步載入的部分,結果只會是比以前載入的更慢了。
由此可見,我在前面講到的SSI和ESI技術對於我們在瀏覽器端發揮CSI技術優點是非常有必要的,SSI和ESI做好了能讓動靜分離出的靜態資源加載的更加高效,這也讓CSI操作的第一個步驟變得高效,第一個步驟處理好了我們只要在頁面控制好腳本阻塞對異步加載的影響,那麼我們就可以達到提升整個頁面加載效率的目的了。另外我覺得CSI對SEO有重大影響是個偽命題,假如使用CSI造成了SEO效果不佳,那麼肯定是我們CSI方案設計的不到位。
有人認為CSI還會有個缺點,不過筆者我並不認為這是缺點,這其實是設計問題,好與壞是根據個人的操作習慣所決定的。這個別人認為的缺點是什麼呢?它就是使用CSI技術時候,雖然頁面很快的被加載出來了,但是動態內容那部分可能會顯示一個正在加載的提示,那麼這就導致頁面用戶友好性降低,其實這種同步和非同步加載混搭操作實在太常見了,幾乎所有大型門戶網站,電商網站還有一大堆數不盡的網站都是採用同步和異步混搭的加載方式,假如這些網站不這麼做,我相信這些網站例如首頁加載一定會慢的讓人吐血,因為它們很多網頁裡面內容實在太多,圖片也都有點爆棚了,所以它們不得不使用同步和異步混搭的加載方式,甚至很多靜態資源例如圖片,flash這些東西也會採取異步加載方式。說到這裡,估計有人還是覺得不服氣,他就是不喜歡頁面載入時候還要出現個正在載入提示,但是網頁裡又非常需要CSI帶來的好處,那麼我們該如何解決這個問題呢?這個問題很好解決,首先願意使用CSI技術也就說明用戶還是很願意使用異步的加載技術的,不喜歡則是正在加載的提示,這說明用戶想要在做同步加載操作時候不要摻雜異步操作,雖然現在ajax技術大行其道,但是ajax技術有個同步加載是沒有辦法解決的,那就是我們在瀏覽器地址欄裡輸入網站url請求頁面,所以面對上面的需求我們只要保證這種同步操作只是一個純粹的同步操作而不要摻雜異步加載即可,這個方案還是很好實施的,這裡我就不再累述了。
動靜分離後我們會把靜態資源進行緩存,前面文章裡講了一大堆都是在講服務端的靜態資源緩存,現在講到了CSI已經到了瀏覽器端,那麼我們就得談談瀏覽器的快取操作。頁面的快取操作就是使用http的expires和cache-control,我們先看看下面的寫法:
<meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0">
這是我現在做的java的web專案裡,jsp和vm檔都會使用的meta配置,它的目的就是讓頁面不要被瀏覽器緩存,但是如果使用CSI技術,同時動靜分離做的很好,那麼在頁面頭部其實我們可以不再這麼寫了,我們可以讓頁面在合理的時間範圍內被瀏覽器緩存,如果該頁面做了快取操作,那麼以後我們再訪問該頁面,網頁的載入效率就會變得更高了。
這裡還有個問題,在雅虎優化網站的建議裡,為了充分利用網頁並行加載的特點,我們往往會把圖片,外部的js和css文件放置在單獨的靜態web容器或CDN上,那麼這些文件往往也是可以被瀏覽器緩存,這個我們又如何設定才能讓瀏覽器知道要快取它們呢?這裡我們以apache為例,為了讓靜態資源被瀏覽器緩存,apache需要使用mod_expires模組,然後在apache的設定檔裡加入如下設定:
<FilesMatch "\.(gif|jpg|png|js|css">ExpiresDefault "access plus 10 years"</FilesMatch>
那麼瀏覽器存取此apache上的靜態資源後,瀏覽器就會把圖片和該伺服器上的js和css檔案快取在瀏覽器裡。
當http的回應碼是304的時候,那麼瀏覽器就會從快取裡讀取資源了,這裡有的朋友可能會感到奇怪為什麼快取的資源還要發送個http請求了?要理解這個我們就要了解下快取的機制,快取的意思是暫時保存某些東西,既然是臨時保存,那麼就應該有個保存的有效期,我們定義快取的方式是透過http完成的,那麼按道理檢查快取是否過期也應該是http來決定的,因此每次使用快取時候我們要發個請求到服務端,服務端會檢查下資源是否過期了,如果沒有過期,服務端回傳個304的回應碼,304的回傳回應是沒有http報文體的,所以這個http請求的回傳資料是非常小的,因此這個http效率還是很高的,如果服務端發現資源過期了那麼服務端就會把新資源回傳給瀏覽器了,其實這個偵測資源是否過期的請求有個專有名詞叫做條件Get請求。至於服務端是如何完成檢查操作,本系列在講web前端優化時候會詳細闡述,這裡就不深入了。看到這裡估計有朋友又有疑問了,為什麼快取是否過期不能在瀏覽器端做了?這主要是瀏覽器做這個檢查非常不準,因為用戶的電腦時鐘不一定準確,或者用戶電腦時鐘和服務端不一致,如果再加上時區那麼就更加麻煩了,所以緩存失效最好是在服務端進行,這樣快取的有效期限的準確性才能得到保證。 html5的出現,瀏覽器快取的能力大大增強了,不過使用html5技術進行快取我還沒有深入研究過,所以這裡也不講述了,有興趣的朋友可以自己研究下。
好了,CSI主題內容講完了,講到CSI技術和瀏覽器我們就可以開始本系列另一個重要內容前後端分離了,這將是我下篇的主題,我在自己博客裡多次講到前後端分離,馬上又要再講了,這次講是我這麼長時間做前後端分離研究的大總結了。