客戶端渲染(CSR)
客戶端渲染意味著在瀏覽器中使用Javascript直接渲染頁(yè)面。所有的邏輯,數(shù)據(jù)獲取,模板和路由都在客戶端處理。
對(duì)于移動(dòng)設(shè)備來(lái)說(shuō),客戶端渲染很難得到或者保持一種快速的訪問(wèn)水平。如果它做最少的工作,保持嚴(yán)格的Javascript預(yù)算,并盡可能減少數(shù)據(jù)請(qǐng)求往返的時(shí)間,那么它可以接近純服務(wù)器端渲染的性能。使用HTTP/2推送或者是<link rel=preload>可以使得關(guān)鍵腳本和數(shù)據(jù)得以更快的傳遞,從而使得解析器更快的為你工作。為了確保初始化和隨后的導(dǎo)航感覺(jué)立刻就能完成,像PRPL這樣的模式就比較值得去做。
?
客戶端渲染主要的缺點(diǎn)就是Javascript的數(shù)量會(huì)隨著應(yīng)用程序的增長(zhǎng)而變得越來(lái)越多。當(dāng)有額外的新Javascript類(lèi)庫(kù),polyfills和第三方代碼的時(shí)候,優(yōu)化工作會(huì)尤其困難。然而這些代碼也會(huì)競(jìng)爭(zhēng)系統(tǒng)的處理能力,因此在頁(yè)面內(nèi)容被渲染完成之前,必須要經(jīng)常處理一些東西。
對(duì)于構(gòu)建單頁(yè)應(yīng)用的人員來(lái)說(shuō),對(duì)于被大多數(shù)頁(yè)面共享的核心用戶接口,你可以嘗試應(yīng)用Application Shell緩存技術(shù)。并與service workers相結(jié)合,它可以明顯提高重復(fù)訪問(wèn)的時(shí)候的感知性能。
通過(guò)rehydration合并服務(wù)器端渲染和客戶端渲染
這種方式通常被稱為“Universal Rendering”或簡(jiǎn)稱為“SSR”,這種方式試圖通過(guò)平滑的方式來(lái)平衡客戶端渲染和服務(wù)器端渲染。諸如全頁(yè)加載或者是重新加載的請(qǐng)求會(huì)在服務(wù)器端被處理,在服務(wù)器端會(huì)把其轉(zhuǎn)為HTML,然后Javascript和渲染所用到的數(shù)據(jù)會(huì)被一起插入到最后的結(jié)果頁(yè)面。如果實(shí)現(xiàn)的好的話,這種方式會(huì)像服務(wù)器端渲染那樣產(chǎn)生一個(gè)很快的First Contentful Paint。服務(wù)器端返回結(jié)果以后,會(huì)在客戶端會(huì)通過(guò)一個(gè)叫(rehydration)的技術(shù)再次渲染。這是一個(gè)比較新的解決方案,但是他可能有比較大的性能缺陷。
rehydration的SSR的主要的缺點(diǎn)就是它對(duì)Time To Interactive有著明顯的缺點(diǎn),即使它會(huì)提高First Paint。它經(jīng)??雌饋?lái)是具有欺騙性的加載和交互,因?yàn)樗鼘?shí)際上在js以及事件處理完成之前,是無(wú)法響應(yīng)輸入的。在手機(jī)端可能會(huì)花費(fèi)數(shù)秒鐘才會(huì)讓頁(yè)面真正可以使用。
你可能經(jīng)歷過(guò)以下問(wèn)題 - 頁(yè)面請(qǐng)求加載一段時(shí)間以后,你的網(wǎng)頁(yè)看起來(lái)已經(jīng)加載好了,但是點(diǎn)擊以后什么都不會(huì)做,你可能很快就會(huì)變得崩潰...“現(xiàn)在到底發(fā)生什么事情了?為什么我不能滾動(dòng)頁(yè)面”。
一個(gè)Rehydration的問(wèn)題:一個(gè)應(yīng)用程序要構(gòu)建兩次
由于JS的原因,Rehydration的問(wèn)題通常要比延遲可用的問(wèn)題要更糟。為了使客戶端的Javascript能夠精確的“獲取”服務(wù)器停止渲染的位置,而不必重新渲染服務(wù)器已渲染過(guò)的HTML,當(dāng)前的SSR解決方案通常會(huì)序列化其UI響應(yīng),并把其依賴的數(shù)據(jù)作為標(biāo)簽放進(jìn)文檔中。HTML文檔的結(jié)果包含一個(gè)更高級(jí)別的重復(fù)。
?
正如你所看到的,在響應(yīng)中服務(wù)器不僅返回一個(gè)應(yīng)用程序UI的描述給瀏覽器,而且還吧相關(guān)的數(shù)據(jù)也一并返回了過(guò)來(lái),當(dāng)啟動(dòng)客戶端的時(shí)候,UI會(huì)再次實(shí)現(xiàn)渲染一次。其只在bundle.js已經(jīng)完成加載和解析以后,UI才會(huì)變?yōu)榭山换サ摹?/p>
在真實(shí)世界中通過(guò)使用SSR來(lái)收集性能指標(biāo),其結(jié)果通常會(huì)比較令人沮喪。原因歸結(jié)于用戶體驗(yàn):它很容易使用戶留在一個(gè)“不可思議的山谷中”。
?
雖然SSR有rehydration的希望。但是是在一個(gè)很短的時(shí)期內(nèi),在更高的可緩存的內(nèi)容中使用SSR可以減少TTFB延遲。產(chǎn)生一個(gè)和預(yù)渲染相似的結(jié)果。遞增的,逐步的,部分的rehydration可能是未來(lái)技術(shù)可用性更高的關(guān)鍵(Rehydrating incrementally, progressively, or partially may be the key to making this technique more viable in the future)。
流服務(wù)器渲染和漸進(jìn)式Rehydration
服務(wù)器端渲染在過(guò)去幾年擁有大量的開(kāi)發(fā)者。
流服務(wù)器渲染允許你以塊的方式發(fā)送HTML,瀏覽器可以通過(guò)接收到的片段進(jìn)行漸進(jìn)式的渲染。由于內(nèi)容可以更快的送達(dá)給用戶,所以他可以帶來(lái)更快的First Paint和First Contentful Paint。在React中,流通過(guò)renderToNodeStream()被異步傳輸 - 相比于同步渲染方式 - 意味著背壓處理效果會(huì)更好。
漸進(jìn)式rehydration也是值得一看的,在一些React已經(jīng)對(duì)此有了一些相關(guān)的探索了。通過(guò)這種方法,服務(wù)器端渲染的每一個(gè)部分內(nèi)容都會(huì)隨著時(shí)間的推移而啟動(dòng),而不是目前通用的方法,通過(guò)一次初始化整個(gè)應(yīng)用程序。這可以幫助我們減少頁(yè)面交互所需要的Javascript的代碼量。因?yàn)榭梢匝泳彽蛢?yōu)先級(jí)客戶端的內(nèi)容過(guò)早的執(zhí)行,以使得防止阻塞主線程的執(zhí)行。它還可以幫助避免最常見(jiàn)的SSR Rehydration陷阱之一,其中服務(wù)器呈現(xiàn)的DOM樹(shù)被破壞然后立即重建 - 通常是因?yàn)槌跏纪娇蛻舳虽秩舅璧臄?shù)據(jù)還沒(méi)有完全準(zhǔn)備好,可能還在等待Promise 解析的完成。
部分Rehydration
部分Rehydration已經(jīng)被證明是難以實(shí)現(xiàn)的。這種方法是漸進(jìn)式rehydration的一種擴(kuò)展。其中逐步分析了漸進(jìn)式的rehydration的每一個(gè)部分。標(biāo)記了那些交互性很小,或者沒(méi)有交互性的那些。對(duì)于每個(gè)幾乎靜態(tài)的部分,對(duì)應(yīng)的Javascript會(huì)被轉(zhuǎn)換為惰性引用或者是裝飾函數(shù)中。將其客戶端占用空間減少到接近為零.部分Rehydration也會(huì)有自己的問(wèn)題和妥協(xié)。它為緩存帶來(lái)了一些有趣的挑戰(zhàn),而客戶端導(dǎo)航意味著我們無(wú)法假設(shè)應(yīng)用程序的惰性部分的服務(wù)器呈現(xiàn)的HTML將在沒(méi)有完整頁(yè)面加載的情況下可用。
Trisomorphic渲染
如果service workers對(duì)于你來(lái)說(shuō)是一個(gè)選項(xiàng)的話。那么對(duì)于“trisomorphic”渲染來(lái)說(shuō),你可能也是感興趣的。這是一種可以將初始/非JS應(yīng)用在流服務(wù)器上的一種技術(shù),然后讓您的服務(wù)工作者在安裝后渲染為HTML以進(jìn)行導(dǎo)航,這可以使緩存的組件和模板保持最新,并啟用SPA樣式導(dǎo)航以在同一會(huì)話中呈現(xiàn)新視圖。當(dāng)您可以在服務(wù)器,客戶端頁(yè)面和服務(wù)器工作程序之間共享相同的模板和路由代碼時(shí),此方法最有效。
?
SEO注意事項(xiàng)
當(dāng)在網(wǎng)站上選擇渲染策略時(shí),團(tuán)隊(duì)通常會(huì)考慮SEO的影響。服務(wù)器端渲染通常被選擇提供一個(gè)對(duì)于爬蟲(chóng)“完全可視”的,更容易爬取的網(wǎng)頁(yè)。爬蟲(chóng)可能會(huì)理解Javascript,但是他們?cè)阡秩局型ǔS兄档米⒁獾南拗???蛻舳虽秩究梢怨ぷ鳎峭ǔ](méi)有額外的測(cè)試工作。最近的動(dòng)態(tài)渲染逐漸成為一個(gè)值得考慮的選項(xiàng),如果你的架構(gòu)很大部分都是由客戶端Javascript驅(qū)動(dòng)的話。
如果有疑問(wèn),移動(dòng)友好測(cè)試工具對(duì)于測(cè)試您選擇的方法是否符合您的預(yù)期非常寶貴。 它顯示了Google抓取工具顯示任何頁(yè)面的方式預(yù)覽,找到的序列化HTML內(nèi)容(執(zhí)行JavaScript后)以及渲染過(guò)程中遇到的任何錯(cuò)誤。
?
總結(jié)
當(dāng)決定渲染的方法的時(shí)候,首先要測(cè)量并且理解你的瓶頸是什么。思考靜態(tài)渲染或者是服務(wù)器端渲染是否可以滿足你90%的需求。用最少的JS發(fā)布HTML也是極好的,其會(huì)得到一個(gè)可交互的用戶體驗(yàn)。下面是一個(gè)方便的信息圖,顯示了服務(wù)器-客戶端頻譜。
?
本文翻譯自:
https://developers.google.com/web/updates/2019/02/rendering-on-the-web
本文轉(zhuǎn)載自http://www.lht.ren/article/14/