web頁面渲染(二)
客戶端渲染(CSR)
客戶端渲染意味著在瀏覽器中使用Javascript直接渲染頁面。所有的邏輯,資料獲取,模板和路由都在客戶端處理。
對於移動裝置來說,客戶端渲染很難得到或者保持一種快速的訪問水平。如果它做最少的工作,保持嚴格的Javascript預算,並儘可能減少資料請求往返的時間,那麼它可以接近純伺服器端渲染的效能。使用HTTP/2推送或者是<link rel=preload>可以使得關鍵指令碼和資料得以更快的傳遞,從而使得解析器更快的為你工作。為了確保初始化和隨後的導航感覺立刻就能完成,像PRPL這樣的模式就比較值得去做。
客戶端渲染主要的缺點就是Javascript的數量會隨著應用程式的增長而變得越來越多。當有額外的新Javascript類庫,polyfills和第三方程式碼的時候,優化工作會尤其困難。然而這些程式碼也會競爭系統的處理能力,因此在頁面內容被渲染完成之前,必須要經常處理一些東西。
對於構建單頁應用的人員來說,對於被大多數頁面共享的核心使用者介面,你可以嘗試應用Application Shell快取技術。並與service workers相結合,它可以明顯提高重複訪問的時候的感知效能。
通過rehydration合併伺服器端渲染和客戶端渲染
這種方式通常被稱為“Universal Rendering”或簡稱為“SSR”,這種方式試圖通過平滑的方式來平衡客戶端渲染和伺服器端渲染。諸如全頁載入或者是重新載入的請求會在伺服器端被處理,在伺服器端會把其轉為HTML,然後Javascript和渲染所用到的資料會被一起插入到最後的結果頁面。如果實現的好的話,這種方式會像伺服器端渲染那樣產生一個很快的First Contentful Paint。伺服器端返回結果以後,會在客戶端會通過一個叫(rehydration)的技術再次渲染。這是一個比較新的解決方案,但是他可能有比較大的效能缺陷。
rehydration的SSR的主要的缺點就是它對Time To Interactive有著明顯的缺點,即使它會提高First Paint。它經常看起來是具有欺騙性的載入和互動,因為它實際上在js以及事件處理完成之前,是無法響應輸入的。在手機端可能會花費數秒鐘才會讓頁面真正可以使用。
你可能經歷過以下問題 - 頁面請求載入一段時間以後,你的網頁看起來已經載入好了,但是點選以後什麼都不會做,你可能很快就會變得崩潰...“現在到底發生什麼事情了?為什麼我不能滾動頁面”。
一個Rehydration的問題:一個應用程式要構建兩次
由於JS的原因,Rehydration的問題通常要比延遲可用的問題要更糟。為了使客戶端的Javascript能夠精確的“獲取”伺服器停止渲染的位置,而不必重新渲染伺服器已渲染過的HTML,當前的SSR解決方案通常會序列化其UI響應,並把其依賴的資料作為標籤放進文件中。HTML文件的結果包含一個更高級別的重複。
正如你所看到的,在響應中伺服器不僅返回一個應用程式UI的描述給瀏覽器,而且還吧相關的資料也一併返回了過來,當啟動客戶端的時候,UI會再次實現渲染一次。其只在bundle.js已經完成載入和解析以後,UI才會變為可互動的。
在真實世界中通過使用SSR來收集效能指標,其結果通常會比較令人沮喪。原因歸結於使用者體驗:它很容易使使用者留在一個“不可思議的山谷中”。
雖然SSR有rehydration的希望。但是是在一個很短的時期內,在更高的可快取的內容中使用SSR可以減少TTFB延遲。產生一個和預渲染相似的結果。遞增的,逐步的,部分的rehydration可能是未來技術可用性更高的關鍵(Rehydrating incrementally, progressively, or partially may be the key to making this technique more viable in the future)。
流伺服器渲染和漸進式Rehydration
伺服器端渲染在過去幾年擁有大量的開發者。
流伺服器渲染允許你以塊的方式傳送HTML,瀏覽器可以通過接收到的片段進行漸進式的渲染。由於內容可以更快的送達給使用者,所以他可以帶來更快的First Paint和First Contentful Paint。在React中,流通過renderToNodeStream()被非同步傳輸 - 相比於同步渲染方式 - 意味著背壓處理效果會更好。
漸進式rehydration也是值得一看的,在一些React已經對此有了一些相關的探索了。通過這種方法,伺服器端渲染的每一個部分內容都會隨著時間的推移而啟動,而不是目前通用的方法,通過一次初始化整個應用程式。這可以幫助我們減少頁面互動所需要的Javascript的程式碼量。因為可以延緩低優先順序客戶端的內容過早的執行,以使得防止阻塞主執行緒的執行。它還可以幫助避免最常見的SSR Rehydration陷阱之一,其中伺服器呈現的DOM樹被破壞然後立即重建 - 通常是因為初始同步客戶端渲染所需的資料還沒有完全準備好,可能還在等待Promise 解析的完成。
部分Rehydration
部分Rehydration已經被證明是難以實現的。這種方法是漸進式rehydration的一種擴充套件。其中逐步分析了漸進式的rehydration的每一個部分。標記了那些互動性很小,或者沒有互動性的那些。對於每個幾乎靜態的部分,對應的Javascript會被轉換為惰性引用或者是裝飾函式中。將其客戶端佔用空間減少到接近為零.部分Rehydration也會有自己的問題和妥協。它為快取帶來了一些有趣的挑戰,而客戶端導航意味著我們無法假設應用程式的惰性部分的伺服器呈現的HTML將在沒有完整頁面載入的情況下可用。
Trisomorphic渲染
如果service workers對於你來說是一個選項的話。那麼對於“trisomorphic”渲染來說,你可能也是感興趣的。這是一種可以將初始/非JS應用在流伺服器上的一種技術,然後讓您的服務工作者在安裝後渲染為HTML以進行導航,這可以使快取的元件和模板保持最新,並啟用SPA樣式導航以在同一會話中呈現新檢視。當您可以在伺服器,客戶端頁面和伺服器工作程式之間共享相同的模板和路由程式碼時,此方法最有效。
SEO注意事項
當在網站上選擇渲染策略時,團隊通常會考慮SEO的影響。伺服器端渲染通常被選擇提供一個對於爬蟲“完全可視”的,更容易爬取的網頁。爬蟲可能會理解Javascript,但是他們在渲染中通常有值得注意的限制。客戶端渲染可以工作,但是通常沒有額外的測試工作。最近的動態渲染逐漸成為一個值得考慮的選項,如果你的架構很大部分都是由客戶端Javascript驅動的話。
如果有疑問,移動友好測試工具對於測試您選擇的方法是否符合您的預期非常寶貴。 它顯示了Google抓取工具顯示任何頁面的方式預覽,找到的序列化HTML內容(執行JavaScript後)以及渲染過程中遇到的任何錯誤。
總結
當決定渲染的方法的時候,首先要測量並且理解你的瓶頸是什麼。思考靜態渲染或者是伺服器端渲染是否可以滿足你90%的需求。用最少的JS釋出HTML也是極好的,其會得到一個可互動的使用者體驗。下面是一個方便的資訊圖,顯示了伺服器-客戶端頻譜。
本文翻譯自: