主要從事網(wǎng)頁(yè)設(shè)計(jì)、PC網(wǎng)站建設(shè)(電腦版網(wǎng)站建設(shè))、wap網(wǎng)站建設(shè)(手機(jī)版網(wǎng)站建設(shè))、響應(yīng)式網(wǎng)站開(kāi)發(fā)、程序開(kāi)發(fā)、微網(wǎng)站、小程序開(kāi)發(fā)等,憑借多年來(lái)在互聯(lián)網(wǎng)的打拼,我們?cè)诨ヂ?lián)網(wǎng)網(wǎng)站建設(shè)行業(yè)積累了豐富的網(wǎng)站建設(shè)、成都網(wǎng)站建設(shè)、網(wǎng)絡(luò)營(yíng)銷(xiāo)經(jīng)驗(yàn),集策劃、開(kāi)發(fā)、設(shè)計(jì)、營(yíng)銷(xiāo)、管理等多方位專(zhuān)業(yè)化運(yùn)作于一體,具備承接不同規(guī)模與類(lèi)型的建設(shè)項(xiàng)目的能力。
我們知道,用戶(hù)體驗(yàn)是 Web 產(chǎn)品最為重要的部分。盡可能減少首屏加載時(shí)間,更為流暢地展示用戶(hù)所需求的內(nèi)容,會(huì)是用戶(hù)是否留存的關(guān)鍵因素。
而隨著現(xiàn)代 Web 業(yè)務(wù)可供用戶(hù)的交互行為越來(lái)越多,前端項(xiàng)目的復(fù)雜度越來(lái)越高,每個(gè)頁(yè)面的渲染時(shí)間也必然越來(lái)越長(zhǎng),這就導(dǎo)致了用戶(hù)的體驗(yàn)不佳,用戶(hù)的操作變慢。
為此,前端工程師們?cè)谑灼琳?qǐng)求的各個(gè)階段中持續(xù)鉆研,不斷探究如何將首次頁(yè)面渲染的時(shí)間減少到更小,力求提供更為優(yōu)秀的產(chǎn)品體驗(yàn)。
瀏覽器渲染是最簡(jiǎn)單,最符合 Web 應(yīng)用設(shè)計(jì)思路的渲染方式。
所謂瀏覽器渲染,就是將應(yīng)用所需的頁(yè)面展示、前端邏輯、接口請(qǐng)求全都在用戶(hù)的瀏覽器中執(zhí)行。它很好的實(shí)現(xiàn)了前后端的解耦,讓前端開(kāi)發(fā)更為獨(dú)立,也讓后臺(tái)實(shí)現(xiàn)更為簡(jiǎn)單。
同時(shí),為了緩解用戶(hù)的等待焦慮,我們可以用 loading 態(tài),或者骨架屏,進(jìn)一步提升異步請(qǐng)求接口時(shí)的用戶(hù)體驗(yàn)。
不過(guò),隨著業(yè)務(wù)復(fù)雜程度提高,瀏覽器渲染的開(kāi)銷(xiāo)也會(huì)變大,我們無(wú)法控制用戶(hù)側(cè)使用的機(jī)器性能,很多時(shí)候,用戶(hù)使用的機(jī)器性能甚至不足以滿(mǎn)足應(yīng)用的需求,造成卡頓,甚至崩潰,這一點(diǎn)在移動(dòng)端上尤甚。
而瀏覽器渲染由于前端的動(dòng)態(tài)性過(guò)高,也會(huì)帶來(lái) SEO 不佳的問(wèn)題。
服務(wù)端渲染的出現(xiàn)時(shí)間實(shí)際上是要比瀏覽器渲染要更早的。在 Web 應(yīng)用發(fā)展的早期,所有的 ASP、JSP 等模板引擎構(gòu)建的前端頁(yè)面實(shí)際上就是服務(wù)端渲染的結(jié)果。而此時(shí)的服務(wù)端渲染無(wú)法進(jìn)行前后端職責(zé)的解耦,因此逐步被瀏覽器渲染淘汰。
但在處理首屏體驗(yàn)的問(wèn)題上,服務(wù)端渲染有著獨(dú)到的優(yōu)勢(shì)。它能提前再服務(wù)端中完成頁(yè)面模板的數(shù)據(jù)填充,從而一次性返回完整的首屏內(nèi)容,從而面對(duì) SEO 的爬取時(shí)能獲取到更多有效的關(guān)鍵信息。
此外,由于其能快速直出首頁(yè)的真實(shí)數(shù)據(jù),體驗(yàn)往往比 loading 態(tài)更佳,在 TTI 的表現(xiàn)上更為出色。
但是,服務(wù)端渲染也有其自身的局限性。因?yàn)閺谋举|(zhì)上來(lái)說(shuō),SSR 服務(wù)無(wú)法完全與前端頁(yè)面解耦開(kāi)來(lái)。因此市面上較完備的 SSR 解決方案都只解決首屏的服務(wù)端渲染,并采用同構(gòu)的方式,增加一層 node 中間層的方式來(lái)解決前端與 SSR 服務(wù)的更新同步問(wèn)題,并與后端開(kāi)發(fā)項(xiàng)目解耦。
但這無(wú)疑增加了項(xiàng)目的復(fù)雜度,并且隨著業(yè)務(wù)的復(fù)雜程度變高,服務(wù)端渲染往往需要調(diào)起多個(gè)接口去請(qǐng)求數(shù)據(jù)并填充頁(yè)面,這樣可能會(huì)導(dǎo)致在 TTFB 上有一定劣勢(shì)。
當(dāng)然,最重要的是,服務(wù)端渲染對(duì)于服務(wù)器的負(fù)載要求是很高的。
上圖是引用的字節(jié)的某項(xiàng)目的 SSR 服務(wù)的單機(jī) QPS 承載表現(xiàn)。我們可以看出,對(duì)于一個(gè)高訪(fǎng)問(wèn)量的網(wǎng)頁(yè)應(yīng)用來(lái)說(shuō),提供一個(gè)較為復(fù)雜的 SSR 服務(wù)的成本是相當(dāng)高的,需要花費(fèi)大量的金錢(qián)來(lái)堆機(jī)器。
因此,從降本增效的角度考慮,我們需要評(píng)估 SSR 帶來(lái)的 ROI 是否符合預(yù)期。
在移動(dòng)互聯(lián)網(wǎng)的浪潮下,移動(dòng)端機(jī)能飛速提升,那么 Web 應(yīng)用是否能搭上這一班車(chē),將 Native 的性能利用起來(lái),提升頁(yè)面渲染性能呢?答案是肯定的,這就需要介紹到 NSR 了。
Native 渲染的本質(zhì)其實(shí)還是 SSR,只不過(guò)提供服務(wù)的 Server 轉(zhuǎn)變?yōu)榱丝蛻?hù)端。由于需要用到客戶(hù)端機(jī)能,因此此種實(shí)現(xiàn)通常應(yīng)用在移動(dòng)端 APP,或者 PWA 下。
當(dāng)鏈接被點(diǎn)擊時(shí),先借助瀏覽器啟用一個(gè) JS 運(yùn)行時(shí),并加載 APP 中存儲(chǔ)的 Html 模板,發(fā)送 xhr 請(qǐng)求預(yù)加載頁(yè)面數(shù)據(jù),從而在客戶(hù)端本地拼接并渲染生成一個(gè)有數(shù)據(jù)的 Html 首屏,形成首次 NSR。同時(shí)可以將該首屏 Html 緩存在客戶(hù)端,供下次頁(yè)面打開(kāi)時(shí),實(shí)現(xiàn) stale-while-revalidate
的緩存效果。
由于 NSR 將服務(wù)器的渲染工作放在了客戶(hù)端的一個(gè)個(gè)獨(dú)立設(shè)備中,既實(shí)現(xiàn)了頁(yè)面的預(yù)加載,同時(shí)又不會(huì)增加額外的服務(wù)器壓力。達(dá)到秒看的效果。
這種能力在擁有客戶(hù)端或者支持 PWA 的應(yīng)用中應(yīng)用廣泛,例如手 Q,騰訊文檔 APP 中都擁有通過(guò) APP 中的離線(xiàn)包來(lái)實(shí)現(xiàn)首屏渲染加速的能力。
那么,對(duì)于純 Web 應(yīng)用,而又由于兼容性等原因暫時(shí)無(wú)法支持 PWA 的頁(yè)面,有沒(méi)有一個(gè)合適的首屏渲染加速方案呢?
隨著云與邊緣計(jì)算的快速發(fā)展,前端頁(yè)面也需要考慮分布式的請(qǐng)求處理優(yōu)化。
我們知道,CDN 節(jié)點(diǎn)相比真實(shí)服務(wù)節(jié)點(diǎn)更貼近用戶(hù),能更快將內(nèi)容返回。因此我們可以將靜態(tài)的 Html 內(nèi)容模板緩存在 CDN 上。當(dāng)接到請(qǐng)求時(shí),先快速將靜態(tài)模板頁(yè)面返回給用戶(hù),同時(shí)在 CDN 服務(wù)器上對(duì)頁(yè)面動(dòng)態(tài)部分發(fā)起向后端發(fā)起請(qǐng)求,并將獲取到的動(dòng)態(tài)內(nèi)容在以流式下發(fā)的方式繼續(xù)返回給用戶(hù)。
這里實(shí)際上利用到了 HTTP 的 SSE(Server Send Events)協(xié)議,通過(guò)服務(wù)器向客戶(hù)端發(fā)送單向事件流,實(shí)現(xiàn)同一個(gè) Html 文件的分塊傳輸預(yù)渲染。
這也是我們最近在騰訊文檔中探索實(shí)踐并落地的,通過(guò)服務(wù)中間節(jié)點(diǎn)的流式下發(fā)能力,實(shí)現(xiàn)多級(jí)首屏渲染加速。
對(duì)于一個(gè)復(fù)雜前端頁(yè)面來(lái)說(shuō),首屏需要加載和運(yùn)算的資源類(lèi)型可能有很多,有需要客戶(hù)端解析并執(zhí)行的 JS 動(dòng)效,也有需要服務(wù)端獲取數(shù)據(jù)直出的數(shù)據(jù)分片展示頁(yè)面。
通常來(lái)說(shuō),客戶(hù)端只能等待服務(wù)端獲取分片數(shù)據(jù),并生成經(jīng)過(guò) SSR 渲染后的 HTML,才能開(kāi)始進(jìn)行 script 解析與 js 資源拉取的行為,最終渲染出完整的頁(yè)面數(shù)據(jù)以及動(dòng)效。
而既然他們所需要的計(jì)算方式不同,那么為什么不能并行來(lái)做呢?
我們可以在版本發(fā)布前,將未經(jīng)過(guò)服務(wù)端直出的模板 HTML 進(jìn)行解析,將需要發(fā)起資源請(qǐng)求的所有的外鏈腳本 url 提取出來(lái),生成一個(gè) HTML Header 結(jié)構(gòu),并將該 Header 內(nèi)容偽裝為正常 HTML 緩存在 CDN 節(jié)點(diǎn)中。
結(jié)合之前我們介紹的 HTTP SSE 協(xié)議,當(dāng)用戶(hù)請(qǐng)求時(shí),我們可以以最快的速度向用戶(hù)返回 CDN 中的 HTML header,從而讓用戶(hù)的瀏覽器提前拉取并解析外鏈資源。于此同時(shí),CDN 節(jié)點(diǎn)將用戶(hù)的請(qǐng)求轉(zhuǎn)發(fā)給真實(shí)的服務(wù)端,從而讓服務(wù)端進(jìn)行真實(shí)數(shù)據(jù)的獲取拼接并返回給客戶(hù)端。
由于客戶(hù)端此時(shí)已經(jīng)提前拉取了外鏈資源,因此收到服務(wù)端分片的 SSR 后,客戶(hù)端可以直接將真實(shí)數(shù)據(jù)渲染到頁(yè)面中,而不需要再次等待外鏈資源的解析。
由于并行的關(guān)系,這樣的 SSR 與 NSR 混合方式能大大降低復(fù)雜頁(yè)面首屏渲染的時(shí)間,提升用戶(hù)體驗(yàn)。
以百度首頁(yè)的請(qǐng)求為例,通過(guò) Chorme Network 提供的瀑布圖,通過(guò)我們可以直觀(guān)的看到一條請(qǐng)求的執(zhí)行過(guò)程。
我們可以看出,除了 DNS 尋址與 SSL 建連是我們無(wú)法控制的以外,占用請(qǐng)求時(shí)間的大頭是 Waiting for server response
,請(qǐng)求服務(wù)器 (CDN) 的時(shí)間,以及 Content Download
,外鏈資源的拉取時(shí)間。
而使用本文的混合方案后,理論上可以使總請(qǐng)求時(shí)間降低到 Max(A, B), (A 為 Waiting for server response
,B 為 Content Download
) 的水平。(當(dāng)然,實(shí)際操作過(guò)程中,由于 CDN 節(jié)點(diǎn)進(jìn)行了一次請(qǐng)求轉(zhuǎn)發(fā),因此擁有 SSR 能力的頁(yè)面請(qǐng)求返回時(shí)間會(huì)更長(zhǎng)一些)。
前端的頁(yè)面首屏?xí)r間優(yōu)化是永恒的話(huà)題,本文介紹了前端界對(duì)首屏?xí)r間優(yōu)化的進(jìn)程,并提供了一種 SSR 與 NSR 混合的新思路,通過(guò)并行處理耗時(shí)任務(wù)的方式,進(jìn)一步提升首屏加載時(shí)間,希望能夠給大家提供一點(diǎn)參考價(jià)值。