精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

新時代的 SSR 框架破局者:qwik

開發(fā) 新聞
qwik 的“無水合”設(shè)計思路目前看來的確會在框架層面帶來巨大的性能提升。

作者簡介

19組清風(fēng),攜程資深前端開發(fā)工程師,負(fù)責(zé)商旅前端公共基礎(chǔ)平臺建設(shè),關(guān)注NodeJs、研發(fā)效能領(lǐng)域。

引言

今天這篇文章中和大家聊一聊號稱世界上第一個 O(1) 的 JavaScript SSR 框架:qwik

別擔(dān)心,如果你不是特別了解 SSR 也沒關(guān)系,文章大概會從以下幾個方面作為切入點:

  • 首先會圍繞對比 SSR 與 SPA 各自的優(yōu)劣勢,從而展開 SSR 的運行機(jī)制以及 SSR 相較于 SPA 究竟為了解決什么問題。
  • 之后,會根據(jù) NextJs 的運行機(jī)制思考針對目前主流 SSR 框架設(shè)計思路上存在的不足從而引出 qwik 為何會在眾多成熟框架中脫穎而出。
  • 最后,會針對于 qwik 提出自己的看法以及聊聊目前 qwik 存在的“問題”。

諸如社區(qū)內(nèi)部 SSR 框架其實已經(jīng)產(chǎn)生了非常優(yōu)秀的作品,比如大名鼎鼎的 NextJS 以及新興勢力代表的 Remix 和 isLands 架構(gòu)的 Astro、Fresh 等等優(yōu)秀框架。

為何 qwik 可以在眾多老牌優(yōu)秀框架中脫穎而出。接下來,讓我們一起來一探究竟吧。

一、SSR & CSR

目前業(yè)內(nèi)存在非常多基于 SSR 的優(yōu)秀框架,比如 Next、Remix、Nuxt 等等。

針對于 Qwik 我們先來聊聊基于 Next 體系的傳統(tǒng) SSR 方案。

1.1 Client Side Rendering

在開始 SSR 之前我們先來聊聊它的對立面,所謂的 CSR(Client Side Rendering)。

服務(wù)器端渲染 (SSR) 是一種在服務(wù)器中進(jìn)行渲染 HTML 而不是由瀏覽器中執(zhí)行 JS 獲得網(wǎng)頁(SPA)的技術(shù)。

目前國內(nèi)社區(qū)中主流框架比如 VueJs、React 等嚴(yán)格意義上來說都是基于 CSR(Client Side Rendering) 的產(chǎn)物。

所謂 CSR 的意味著當(dāng)發(fā)出一個請求時,服務(wù)器會返回一個空的 HTML 頁面以及對應(yīng)的 JavaScript 腳本。

比如:

<html>
<head>
<title>攜程商旅</title>
</head>

<body>
<div id="root"> </div>
<script src="./index.js"> </script>
</body>
</html>

當(dāng)瀏覽器下載完成對應(yīng)的 JS 腳本后才會動態(tài)執(zhí)行對應(yīng)的 JS 腳本然后在返回的 HTML 頁面上進(jìn)行渲染頁面內(nèi)容。

你可以簡單的理解為上述的 ./index.js 會在客戶端下載完成后執(zhí)行該腳本,從而執(zhí)行 document.getElementById('root').innerHTML = '...' 來進(jìn)行頁面渲染。

這種方式并不是從服務(wù)端下發(fā)的 HTML 文件來進(jìn)行渲染頁面,相反而是通過瀏覽器獲取到服務(wù)端下發(fā) HTML 中的所有的 JS 文件后執(zhí)行 JS 代碼從而在客戶端通過腳本進(jìn)行頁面渲染。

以及通常在 CSR 中當(dāng)我們點擊任何頁面中的導(dǎo)航鏈接并不會向服務(wù)端發(fā)起請求,而是通過下載的 JS 腳本中的路由模塊(比如 ReactRouter、VueRouter 這樣的模塊)重新執(zhí)行 JS 來處理頁面跳轉(zhuǎn)從而進(jìn)行頁面重新渲染。

上面的概念是非常典型的 CSR ,瀏覽器僅僅接受一個用作網(wǎng)頁容器的 HTML 頁面,這樣的方式通常也被稱為單頁面應(yīng)用 (SPA)。

1)優(yōu)勢

那么上述我們提到的 CSR 廣泛存在于目前大量頁面中,必然存在它自己的優(yōu)勢。

在頁面初始化訪問后加載速度極快且響應(yīng)非常迅速。在頁面初始化后,網(wǎng)站所有的 HTML 內(nèi)容都是在客戶端通過執(zhí)行 JS 生成,并不需要再次請求服務(wù)器即可重新渲染 HTML 。

此外,有關(guān)任何實時的數(shù)據(jù)獲取都可以通過 AJAX 請求對于頁面進(jìn)行局部更新從而刷新頁面。

2)劣勢

可是,CSR 真的有那么完美嗎。任何一件技術(shù)方案一定存在它的兩面性,我們來看看 CSR 方式究竟存在哪些問題:

  • 初始加載時間長。

首次請求完服務(wù)器獲取到 HTML 頁面后,初始化的頁面仍然需要在一段時間內(nèi)處于白屏狀態(tài)。

在初始渲染之前,瀏覽器必須等待 HTML 頁面中的所有 Javascript 腳本加載完成并且執(zhí)行完畢,此時頁面才會進(jìn)行真正的渲染。

當(dāng)然,使用代碼拆分或延遲加載等多種方案可以有效的減少上述的問題。但是這些方式始終是治標(biāo)不治本,因為它并沒有從本質(zhì)上解決 CSR 存在的問題。

  • SEO(搜索引擎優(yōu)化) 的負(fù)面影響。

上邊我們提到過,所謂 CSR 本質(zhì)上首先會返回一個空的 HTML 頁面,所以這也就造成了在搜索引擎對于該頁面的數(shù)據(jù)爬取中會認(rèn)為它是一個空頁面。從而影響對應(yīng)的搜索結(jié)果排名。

雖然說在最新的 Google 中已經(jīng)可以觸發(fā)執(zhí)行 JS 對于網(wǎng)站進(jìn)行關(guān)鍵字排名,但是在 JS 體積足夠大的時候針對于 SEO 仍然是存在一部分問題導(dǎo)致無法解析出正確的關(guān)鍵字匹配。

當(dāng)然 CSR 還存在一些其他方面的缺點,比如網(wǎng)站強(qiáng)依賴于 JS 當(dāng)用戶禁用 JS 時網(wǎng)站只能是白屏展現(xiàn)給用戶等等之類。

1.2 Server Side Render

簡單聊完客戶端渲染后,我們稍微來看看所謂的服務(wù)端渲染是什么含義。

基于舊時代的類似 Java 的 JSP 頁面我在這里就不贅述了,顯然 JSP 的方式每個 HTML 都需要單獨請求服務(wù)器返回對應(yīng)的 HTML 內(nèi)容嚴(yán)格意義上來說這也是 SSR 的方式但是很明顯這已經(jīng)被時代淘汰了。

目前國內(nèi)各家公司廣泛應(yīng)用的服務(wù)端渲染技術(shù)大概的思路是這樣的(Next 的 SSR 模式也是同樣的思路):

當(dāng)用戶首次訪問你的應(yīng)用站點時:

  • 首先服務(wù)器會根據(jù)對應(yīng)的 URL 在服務(wù)端根據(jù)對應(yīng)路徑渲染對應(yīng)的 HTML 模版。注意這里渲染的 HTML 模版是具有該頁面真正的內(nèi)容。同時它并不具備任何交互邏輯(比如 DOM 元素的點擊事件),這是一份完全的靜態(tài)站點。
  • 服務(wù)器會下發(fā)這份僅具有靜態(tài)內(nèi)容的 HTML 模版,同時這份模版中也會包含對應(yīng)的 JavaScript 執(zhí)行腳本。第一時間會展示給用戶對應(yīng)的 HTML 頁面,此時對于訪問站點的用戶來說首屏渲染相較于 SPA 應(yīng)用來說會非常快。因為它并不需要在客戶端瀏覽器上再次下載和執(zhí)行 JavaScript 腳本來進(jìn)行頁面渲染。
  • 其次,針對于 SEO 的優(yōu)化也會非常良好,因為服務(wù)器上下發(fā)的 HTML 頁面是包含當(dāng)前站點的真實 HTML 結(jié)構(gòu),對于搜索引擎的爬蟲來說會非常容易的匹配到當(dāng)前關(guān)鍵字。
  • 之后,瀏覽器會下載當(dāng)前這份 HTML 的 JS 腳本。
  • 因為首先呈現(xiàn)給用戶的一份靜態(tài)的 HTML 頁面,并不具備任何交互效果。我們需要為頁面上的元素增加對應(yīng)交互,HTML 頁面中的 JS 腳本中會包含網(wǎng)站的交互邏輯。
  • 最后,當(dāng)下載完 HTML 腳本中的 JS 腳本后,自然會執(zhí)行這些 script 腳本。從而發(fā)生一種被稱為 # hydrate(水合) 的方式,從而為頁面上靜態(tài) HTML 元素再次添加對應(yīng)的事件處理從而保證頁面具有交互性。

當(dāng) hydration 過程完成后,會由我們的客戶端框架接管網(wǎng)站的后續(xù)渲染。在后續(xù)的導(dǎo)航鏈接跳轉(zhuǎn)和頁面渲染中和服務(wù)器已經(jīng)沒有任何關(guān)系了,我們完全可以利用客戶端的路由切換(History Api/Hash Api)利用 JS 進(jìn)行頁面渲染從而保證切換頁面不用再次請求瀏覽器保證非常及時的頁面交互。

1)hydration

上述過程中有一個非常重要的關(guān)鍵字 hydration(水合)。

首次訪問頁面時,頁面的靜態(tài) HTML 是在服務(wù)端生成的。在服務(wù)端我們將生成的靜態(tài) HTML 以及 HTML 中攜帶的 JS 腳本發(fā)送到客戶端。

此時靜態(tài) HTML 會立即顯示在用戶視野中,然后瀏覽器會利用網(wǎng)絡(luò)進(jìn)程下載當(dāng)前 HTML 腳本中的 JS 腳本。

當(dāng) JS 腳本下載完成后,會立即執(zhí)行同時發(fā)生一種被稱為 hydration 的過程。

所謂的 hydration 簡單來說,也就是客戶端下載完成 JS 腳本后,瀏覽器會執(zhí)行下載的 JS 腳本這些腳本中有部分內(nèi)容會將已經(jīng)存在的 HTML 內(nèi)容通過執(zhí)行下載的 JS 腳本添加上對應(yīng)的事件監(jiān)聽器從而保證頁面的交互。

注意,在 React、Vue 中 hydration 并不意味著重新渲染。因為在 Server 端已經(jīng)渲染了和 Client 完全相同的 DOM 結(jié)構(gòu)所以完全沒有必要在此重新渲染。

所以 hydration 的過程是給當(dāng)前頁面中已經(jīng)生成的 HTML 頁面添加上對應(yīng)的事件監(jiān)聽器。

這也是為什么在 Next 等框架中為什么必須要保證 Server 端和 Client 的渲染 HTML 結(jié)構(gòu)必須一致的原因。

比如我們以 Next 舉例來說(Vue 也是同樣的道理):

  • 當(dāng)用戶訪問 ?www.trip.biz? 時,服務(wù)端接收到請求調(diào)用 ReactDOMServer.renderToString() 生成當(dāng)前頁面的 HTML 靜態(tài)結(jié)構(gòu)。
  • 服務(wù)器會下發(fā)這個 HTML 頁面給客戶端,同時這個 HTML 頁面上也會攜帶一部分 JS 腳本 script 標(biāo)簽。
  • 用戶的瀏覽器中會立即展現(xiàn)到該 HTML 頁面,同時也會下載對應(yīng) JS 腳本并執(zhí)行。
  • 當(dāng) JS 腳本執(zhí)行完畢后,客戶端會調(diào)用 ReactDOM.hydrate() 發(fā)生水合為當(dāng)前頁面的 HTML 頁面添加事件交互處理,同時后續(xù)由 JS 接管頁面的跳轉(zhuǎn)渲染。

針對于第一步 Next 中存在 ??Automatic Static Optimization?? 的優(yōu)化,并不一定會在每次訪問時調(diào)用 renderToString 方法,有可能在構(gòu)建時也會直接生成對應(yīng)的 HTML 模版。

當(dāng)然,在最新的 Next 版本中已經(jīng)支持了Stream以及 Server Components。

整個過程就像是這張圖中的樣子:

圖片

2)優(yōu)勢

簡單聊過了所謂 SSR 的原理后,如果你有認(rèn)真看上述的內(nèi)容。其實我相信相較于 CSR ,SSR 這種方式的好處不言而喻:

  • 更好的搜索引擎優(yōu)化 SEO 方式,HTML 模板是從服務(wù)端直接下發(fā)這也就導(dǎo)致搜索引擎爬蟲中更多的關(guān)鍵字匹配。
  • 更快的首屏渲染,因為相較于 SPA 它少了在 Client 中下載和執(zhí)行 JS 腳本后渲染的過程。
  • 頁面不需要 JS 也可以正常渲染,雖然沒有 JS 意味著頁面失去了可交互性。但對于禁用 JS 的用戶來說,展示一些靜態(tài)內(nèi)容總比 SPA 應(yīng)用的白屏來的更加友好一些對吧。

3)劣勢

當(dāng)然,任何技術(shù)方案在不同場景下也存在它自己的不足。

  • 強(qiáng)依賴于服務(wù)。

    針對于 CSR 的方式它是一種純靜態(tài)資源。我們可以直接將它放在 CDN 上就可以良好的用戶訪問到,而 SSR 的方式必須依賴于一個服務(wù)器進(jìn)行服務(wù)端預(yù)渲染。(當(dāng)然純 SSG 應(yīng)用我們不在這個討論范圍之內(nèi))
    同時,有服務(wù)的地方就存在并發(fā)壓力。當(dāng)你需要為你的應(yīng)用考慮服務(wù)端渲染的方式時,一定不要忘記為你的服務(wù)器進(jìn)行壓測。
  • ??Time to Interactive?? 可交互時間 (TTI) 的增長,雖然說 SSR 的方式有效的縮短了首屏加載的方式,但是會增加所謂的TTI(可交互時間)。

    所謂的 TTI 指標(biāo)測量頁面從開始加載到主要子資源完成渲染,并能夠快速、可靠地響應(yīng)用戶輸入所需的時間。

    因為 SSR 的方式在用戶訪問時會下發(fā)當(dāng)前頁面中靜態(tài)的 HTML 內(nèi)容,也就是所謂的 ?First Contentful Paint? 首次內(nèi)容繪制 (FCP) 會非常快速,但是頁面需要用戶交互效果又需要下載和執(zhí)行完成 JS 腳本發(fā)生 hydatrion 后才具有交互性。

    這也就造成頁面的 TTI 相較于 CSR 方式會有所差勁,因為 CSR 在渲染完成后就會立即具有交互性(不需要其他任何多余步驟)。

1.3 qwik

上述聊了那么多前置內(nèi)置,終于要和大家切入正題了。

所謂磨刀不費砍柴功,上邊和大家強(qiáng)調(diào)現(xiàn)階段 SSR 的方案以及對應(yīng)的優(yōu)劣勢就是為了引入下面的內(nèi)容。

首先,這篇文章的目的是為了讓大家在當(dāng)前眾多 SSR 框架中思考性能方面是否可以有所提升的,在服務(wù)器方面不會過多的深入。

我們可以稍微思考下上述服務(wù)器端渲染的過程:

圖片

第一步我們需要在服務(wù)端獲取對應(yīng)頁面的 HTML 頁面,大多數(shù)情況(非純靜態(tài)頁面)就需要在服務(wù)端掉用對應(yīng)渲染方法渲染出 HTML 頁面。

那么,如果我們能在第一步渲染 HTML 頁面時,就添加對應(yīng)的事件處理。后續(xù)的 3 步是不是完全可以省略下來了對吧。

其實社區(qū)內(nèi)部之前已經(jīng)有非常多的方案來提升所謂 SSR 框架的性能方案。

比如 Remix 的 HTTP stale-while-revalidate 緩存指令

比如 astro 等新興框架的 Islands 架構(gòu)方案,關(guān)于 Islands 有興趣的朋友可以參考神三元的這篇 Islands 架構(gòu)原理和實踐。

針對于上面的概念,我們直接來看看 qwik 中提到的 Hydration is Pure Overhead (完全多余的 Hydration)。

1)Hydration 造成的開銷

首先針對于 Hydration 的過程,我們提過到首先會在服務(wù)器上進(jìn)行一次靜態(tài) HTML 渲染,之后當(dāng) HTML 下發(fā)到客戶端后又會再次進(jìn)行 hydrate 的過程,在客戶端進(jìn)行重新執(zhí)行腳本添加事件。

Hydration 過程的難點就在于我們需要知道需要什么事件處理程序,以及將該事件處理程序附加在哪個對應(yīng)的 DOM 節(jié)點上。

這個過程中,我們需要處理:

  • 每一個事件處理程序中的內(nèi)容,絕大多數(shù)框架中的狀態(tài)都作為閉包函數(shù)保存在內(nèi)容中。所以需要 hydration 的過程來重新獲取狀態(tài)。
  • 其次,在搞清楚了每個事件處理函數(shù)的內(nèi)容后。我們也需要將對應(yīng)的事件處理函數(shù)附加到對應(yīng)的 DOM 節(jié)點上,同時還要確保該監(jiān)聽器的正確事件類型。

更加復(fù)雜每個事件處理函數(shù)中的內(nèi)容是一個閉包函數(shù),這個函數(shù)內(nèi)部需要處理兩種狀態(tài),APP_STATE 以及 FRAMEWORK_STATE。

  • APP_STATE:應(yīng)用程序的狀態(tài)。簡單來說應(yīng)用程序的狀態(tài)就是 HTML 事件中的各個狀態(tài)事件,如果不存在這些事件狀態(tài)那么所有的內(nèi)容都是沒有任何交互效果的。
  • FRAMEWORK_STATE:框架內(nèi)部狀態(tài)。通常我們會利用諸如 React 或者 Vue 等框架進(jìn)行接替渲染。如果沒有 FRAMETER_STATE,框架內(nèi)部就不知道應(yīng)該更新哪些DOM節(jié)點,也不知道應(yīng)該在什么時候更新它們。

通俗來說 Hydration 就是在客戶端重新執(zhí)行 JS 去修復(fù)應(yīng)用程序內(nèi)部的 APP_STATE 以及 FRAMEWORK_STATE。

同樣還是這這張圖:

圖片

在圖中的前三個階段可以被稱為 RECOVERY 階段,這三個階段主要是在重建你的應(yīng)用程序。

當(dāng)從 Server 端下發(fā)的 HTML 靜態(tài)頁面后,我們希望它是具有交互效果的 HTML 正常應(yīng)用程序。

那么此時 hydartion 的過程必須經(jīng)歷下載 HTML 、下載所有相關(guān) JS 腳本、解析并且執(zhí)行下載的 JS 腳本。

RECOVERY 階段是和 hydartion 的頁面的復(fù)雜性成正比,在移動設(shè)備上很容易花費 10 秒。

由于RECOVERY是昂貴的部分,大多數(shù)應(yīng)用程序的啟動性能都不是最佳的,尤其是在移動設(shè)備上。

前三個階段被稱為 RECOVERY 的階段其實是完全沒有必要的,因為在服務(wù)端我們已然渲染過對應(yīng)的 HTML ,但是為了應(yīng)用程序的可交互性以及服務(wù)端僅保留了靜態(tài)的 HTML 模版導(dǎo)致不得不在 Client 上繼續(xù)執(zhí)行一次 Server 端的邏輯。

總而言之,hydration 其實是通過下載并重新執(zhí)行 SSR/SSG 呈現(xiàn)的 HTML 中的所有 JS 腳本并執(zhí)行來恢復(fù)組建中的事件處理程序。

同一個應(yīng)用程序,會被發(fā)送到客戶端兩次,一次作為 HTML,另一次作為 JavaScript。

此外,框架必須立即執(zhí)行 JavaScript 以恢復(fù)在服務(wù)器上被丟掉的 APP_STATE和FRAMEWORK_STATE。所有這些工作只是為了檢索服務(wù)器已經(jīng)擁有但丟棄的東西!!

比如這樣一個例子:

export const Main = () => <>
<Greeter />
<Counter value={10}/>
</>


export const Greeter = () => {
return (
<button notallow={() => alert('Hello World!'))}>
Trip Biz
</button>
)
}


export const Counter = (props: { value: number }) => {
const store = useStore({ count: props.number || 0 });
return (
<button notallow={() => store.count++)}>
{store.count}
</button>
)
}

上邊的例子中我們編寫了一個 Counter 的計數(shù)器組件,在傳統(tǒng) SSR 過程中該組件會被渲染成為:

<button>Greet</button>
<button>10</button>

可以看到上邊的兩個按鈕不擁有任何處理狀態(tài)的能力

要使網(wǎng)頁具有交互性,必須要做的就是通過下載對應(yīng) HTML 頁面中的 script 腳本并執(zhí)行代碼從而恢復(fù)按鈕上的交互邏輯和狀態(tài)。

為了具有交互性,客戶端不得不執(zhí)行代碼實例化組件后重新創(chuàng)建狀態(tài)。

當(dāng)上述過程完成后,你的應(yīng)用程序才會真正具有可交互性。無疑,同一個組件的渲染邏輯被執(zhí)行了兩遍,這是一個非常冗余且耗費性能的過程。

2)Resumability: 更加優(yōu)雅的 hydartion 替代方案

所以為了消除額外的開銷,我們需要思考如何避免重復(fù)的 RECOVERY 階段。同時還要避免上面的第四步,第四步是執(zhí)行腳本后給現(xiàn)有的 HTML 附加正確的事件處理程序。

qwik 中提出了一個全新的思路來規(guī)避 RECOVERY 帶來的外開銷:

  • 將所有必需的信息序列化為 HTML 的一部分。qwik 將需要的狀態(tài)以及事件序列化保存在 Server 端下發(fā)的 HTML 模版中,需要序列化信息需要包括WHAT(事件處理函數(shù)內(nèi)容), WHERE(哪些節(jié)點需要哪些類型的事件處理函數(shù)), APP_STATE(應(yīng)用狀態(tài)), 和FRAMEWORK_STATE(框架狀態(tài))。
  • 依賴于事件冒泡來攔截所有事件的全局事件處理程序。qwik 中事件處理程序是在全局處理的,這樣我們就不必在特定的 DOM 元素上單獨注冊所有事件。
  • qwki 內(nèi)部存在一個可以延遲恢復(fù)事件處理程序的工廠函數(shù)。
    該工廠函數(shù)主要用于處理 WHAT 階段,也就是用來識別某個事件處理函數(shù)中應(yīng)該存在什么腳本邏輯。

圖片

我們可以看到所謂的 Resumable 對比 Hydration 明顯可以省略不需要后三個階段,直接獲取 HTML 后頁面其實就已經(jīng)準(zhǔn)備完畢,這無疑對于性能的提升是巨大的。

對比傳統(tǒng)的 hydration 方案,在客戶端獲得服務(wù)端下發(fā)的 HTML 后會立即請求需要的 JS 腳本并執(zhí)行從而為頁面附加對應(yīng)的交互效果。

而 qwik 提出的概念恰恰相反,獲取完服務(wù)端下發(fā)的 HTML 頁面后所有的交互效果實際上都是一種惰性創(chuàng)建的效果。

因為我們在 HTML 中的每個元素中都已經(jīng)通過序列化從而在它的標(biāo)簽屬性上記錄了對應(yīng)事件處理函數(shù)的位置以及腳本內(nèi)容(自然內(nèi)容中也包含對應(yīng)的狀態(tài)),所以當(dāng)獲得 HTML 頁面后其實就可以說此時頁面已經(jīng)加載完畢了而不需要任何實時的 JS 執(zhí)行。

這樣做的好處是在 qwki 中完全可以省略 hydration 的多余步驟,甚至可以說完全拋棄了 hydration 的概念。

客戶端完全不必和服務(wù)端的 HTML 進(jìn)行水合,相同的渲染內(nèi)容僅僅是在 Server 端進(jìn)行一次渲染客戶端即可擁有對應(yīng)的事件處理內(nèi)容。

簡單來講Qwik的工作原理就是在服務(wù)端序列化 HTML 模版,從而在客戶端延遲創(chuàng)建事件處理程序,這也是它為什么非常快速的原因。

3)qwik 工作機(jī)制

上邊我們講到了 qwik 的原理部分,同樣拿上邊的計數(shù)器的例子我們來對比下:

export const Main = () => <>
<Greeter />
<Counter value={10}/>
</>


export const Greeter = () => {
return (
<button notallow={() => alert('Hello World!'))}>
Trip Biz
</button>
)
}


export const Counter = (props: { value: number }) => {
const store = useStore({ count: props.number || 0 });
return (
<button notallow={() => store.count++)}>
{store.count}
</button>
)
}

在 qwik 編譯后,服務(wù)端會序列化對應(yīng)組件的 HTML 結(jié)構(gòu)從而下發(fā)如下的模板:

<div q:host>
<div q:host>
<button on:click="./chunk-a.js#button">Trip Biz</button>
</div>
<div q:host>
<button q:obj="1" on:click="./chunk-b.js#count[0]">10</button>
</div>
</div>
<script id="qwikloader">/* qwik 中設(shè)置全局事件監(jiān)聽器的代碼 */</script>
<script id="qwik/json">/* 用于反序列化的 JSON 相關(guān)信息 */</script>

我們可以看到經(jīng)過 qwik 編譯后的 html 結(jié)構(gòu)并不單單只有 DOM 元素,同時會在對應(yīng)需要狀態(tài) & 事件的 DOM 元素上通過 HTML 元素屬性來記錄當(dāng)前元素的事件和狀態(tài)信息,這既是 qwik 中的序列化。

比如上邊 button 的 on:click 屬性記錄了該元素后續(xù)需要恢復(fù)的所有信息。

需要注意的是序列化這一步是在服務(wù)端渲染時完成的,這也就意味著后續(xù)客戶端可以通過服務(wù)端序列化的屬性信息進(jìn)行反序列化從而達(dá)到所謂的可恢復(fù)性而不需要重復(fù)執(zhí)行組件。

當(dāng)然你可能會好奇 qwik 是如何進(jìn)行這些事件 & 狀態(tài)的恢復(fù),qwik 正是通過在返回的 HTML 頁面中內(nèi)嵌的所謂 qwikloader 的 script 腳本(這段腳本的大小不超過 1kb)配合 qwikjson 映射表,從而在全局進(jìn)行恢復(fù)事件和狀態(tài)的邏輯。

正因為這個原因,使得 qwik相較于傳統(tǒng) SSR 的 hydration 在 Client 中再次執(zhí)行渲染從而水合頁面狀態(tài)和事件處理程序,這簡直可以說是接近零 JS 的執(zhí)行過程。

最終在用戶觸發(fā)事件時候達(dá)到惰性的創(chuàng)建事件并執(zhí)行,這個過程中完全沒有重復(fù)任何服務(wù)器已經(jīng)完成的任何工作。

整個工作過程就像下面這張圖描述的那樣:

圖片

上邊的這張圖完美的描述了 qwik 的工作原理,相信經(jīng)過上述的描述大家對于這張圖中想表達(dá)的思想已經(jīng)可以完美的理解了。


利用 qwik 的這個優(yōu)勢,在絕大多數(shù)應(yīng)用中我們可以利用 qwik 保證你的 SSR 應(yīng)用在保證快速的 FCP 的前提也同樣擁有與之不相上下的 TTI 體驗效果。

4)惰性加載腳本會影響用戶交互體驗嗎

當(dāng)然上文說過任何框架的優(yōu)勢和劣勢都不是絕對的,在我們看來 qwik 的確會存在以下一些問題。

大多數(shù)同學(xué)看完上邊的內(nèi)容我相信也會存在“惰性加載腳本會影響用戶交互體驗嗎”這樣的疑問。

首先,qwik 中既然選擇在觸發(fā)用戶行為時,再惰性加載并執(zhí)行響應(yīng)的 JS 腳本。那么難免需要在用戶觸發(fā)交互時動態(tài)生成對應(yīng)的事件處理函數(shù)進(jìn)行執(zhí)行。

這樣的方式相較于傳統(tǒng) hydration 的確會存在一些不足,需要額外生成事件會額外造成交互響應(yīng)時間的損耗而傳統(tǒng) SSR 方式在頁面首次加載時就已經(jīng)綁定好(相當(dāng)于生成了)相應(yīng)的事件處理函數(shù)。

就惰性加載生成事件這點:

針對于動態(tài)加載 JS 腳本,其實已經(jīng)存在諸如非常多的 prefetch 等等預(yù)加載技術(shù)。

無論是基于傳統(tǒng) Next 方案還是基于 qwik 這種惰性可恢復(fù)的方案,利用 prefetch 等預(yù)加載技術(shù)優(yōu)先在網(wǎng)絡(luò)空閑時加載響應(yīng)重要的 JS 腳本都是非常有必要的,所以這點在我看來并不是特別重要的問題。

5)延遲加載會帶來 bundle 數(shù)量的上升嗎

qwik 推崇的延遲加載其實已經(jīng)是一項非常成熟的構(gòu)建技術(shù)了。無論是使用 webpack、rollup 又或是其他任何構(gòu)建工具都存在延遲加載 & 代碼分割的技術(shù)。

傳統(tǒng)構(gòu)建工具中關(guān)于代碼分割會帶來以下兩點的困難:

  • 需要開發(fā)人員自行去處理更加細(xì)粒度的代碼分割,當(dāng)然這并不是最主要的。因為目前我們可以利用 ?Magic Comments? 配合 ?Dynaic Imports? 來解決需要手動切入多個入口點的問題。

當(dāng)然,這一系列事情比起魔法注釋。因為 qwik 本身提倡的就是所謂的延遲加載,所以在框架內(nèi)部已經(jīng)幫我們足夠智能的去處理這個過程。

但是需要注意的是這并不意味著開發(fā)者無法自主去控制這個過程。只是在使用框架的過程中,qwik 希望開發(fā)者更加專注于他們自身的業(yè)務(wù)邏輯。

  • 當(dāng)存在非常多的延遲加載時,傳統(tǒng)構(gòu)建工具會從一個大 bundle 分割成為無數(shù)個小的 bundle 。

延遲加載模塊的確會存在多個 small bundle 的問題,可是當(dāng)我們擁有的 bundle 越多,其實我們就擁有更多的自由度去以各種各樣的方式去拼裝成為單個大的 bundle。

qwik 中存在足夠的方式提供給我們將多個小的 chunk 自由組合成為一個從而有效的減少細(xì)碎 chunk 的數(shù)量,當(dāng)然這個點在傳統(tǒng)構(gòu)建工具中也是這樣。

6)動態(tài)創(chuàng)建事件函數(shù)會造成內(nèi)存泄漏嗎

qwik 的設(shè)計思想在與每次事件觸發(fā)時通過 qwikloader 來動態(tài)創(chuàng)建事件處理函數(shù),相信有的同學(xué)存在疑問“那么多次觸發(fā)事件會造成額外的開銷嗎”。

qwik 的作者 mi?ko hevery 在 ??Hydration is Pure Overhead?? 中明確的表示過 qwik 會在每次事件執(zhí)行完畢后釋放函數(shù),相當(dāng)于每次事件執(zhí)行完畢都會進(jìn)行一次“去水合”的過程。

所以,當(dāng)你觸發(fā)一次事件和無數(shù)次事件函數(shù)在執(zhí)行過程中對于內(nèi)存占用來說是相差無幾的。

當(dāng)然相較于傳統(tǒng) hydration 的方式(在頁面首次渲染時在內(nèi)存中記錄所有狀態(tài)),無疑 qwik 這種并不在內(nèi)存中記錄任何狀態(tài)的方式恰恰對于內(nèi)存的占用比 dyration 更加輕量化。

7)qwik 真的有那么快嗎

說了那么多,那么 qwik 真的有那么快嗎。

圖片

上圖是利用 qwik 搭建的 ??builder.io?? 官方網(wǎng)站,我相信 builder.io 的數(shù)據(jù)已經(jīng)告訴我們答案了。

固然上述的數(shù)據(jù)并不僅僅只是單純一個 qwik 框架帶給網(wǎng)站的優(yōu)化,一定會有代碼層面或者構(gòu)建層面等等方面的優(yōu)化配合而來的數(shù)據(jù)。但是針對于 FCP 和 TTI 時間上的一致性這在一個中型 SSR 應(yīng)用程序其實可以稱得上是非常優(yōu)秀了,我相信這足以說明了 qwik 的確名副其實。

二、結(jié)語

我們可以看出來,qwik 的核心思路還是通過更加細(xì)粒的代碼控制配合惰性加載事件處理程序以及事件委托來縮短首屏 TTI。

文章中我們也講到了 qwik 其實并不是因為使用了多么牛逼的算法導(dǎo)致它有多么快,而它的速度正是得益于它的設(shè)計思路,省略了傳統(tǒng) SSR 下首屏需要加載龐大的 JS 進(jìn)行 hydration 的過程。

當(dāng)然,我們對于 qwik 也仍是在學(xué)習(xí)階段。后續(xù)會在公司里的更多項目嘗試 qwik 之后也會和大家分享關(guān)于它的更多心得。

總而言之,qwik 的“無水合”設(shè)計思路目前看來的確會在框架層面帶來巨大的性能提升。大家如果有機(jī)會的話也可以在項目中嘗試一下 qwik ,相信會給你帶來意想不到的收益效果。

責(zé)任編輯:張燕妮 來源: 攜程技術(shù)
相關(guān)推薦

2025-06-23 11:50:06

2018-04-16 05:29:35

CDNCDN牌照互聯(lián)網(wǎng)

2021-08-27 09:35:18

邊緣安全

2022-04-19 16:16:35

DevOps云原生容器

2024-01-30 09:08:07

PoetryPython包管理工具

2018-10-31 09:43:22

2015-09-25 16:36:03

埃維諾

2011-08-05 16:21:24

2011-07-22 16:25:38

CA TechnoloIT消費化

2016-11-29 17:13:25

大數(shù)據(jù)

2015-12-28 10:44:22

4G+運營商

2017-09-27 13:54:11

即時通訊網(wǎng)易云

2015-02-02 14:06:33

微軟win10

2010-04-23 15:07:08

云計算

2025-02-20 08:10:00

網(wǎng)絡(luò)安全BlackLock勒索軟件

2011-05-25 10:19:17

2025-06-23 15:55:46

2023-05-04 10:43:42

Qwik前端框架
點贊
收藏

51CTO技術(shù)棧公眾號

国产精品88a∨| 亚洲精品国产精品久久清纯直播| 免费久久久久久| 不卡的日韩av| 久久先锋资源| 美女精品视频一区| 波多野结衣 在线| 国产精品一区二区精品视频观看| 亚洲国产精品一区二区久久恐怖片| 老牛影视免费一区二区| 亚洲永久精品视频| 国产精品女主播一区二区三区| 少妇av一区二区三区| 香港三日本8a三级少妇三级99| 欧美日韩尤物久久| 亚洲国产综合色| 亚洲欧美久久234| 五月激情丁香婷婷| 国产一区在线看| 国产精品v片在线观看不卡| 成人观看免费视频| 日韩中文首页| 亚洲美女在线视频| 亚洲国产精品第一页| 福利精品一区| 色综合一区二区三区| 日本wwwcom| 美女羞羞视频在线观看| 久久久久久久久岛国免费| 成人自拍爱视频| 一级特黄aa大片| 日韩中文欧美在线| 欧美一级片一区| 久久草视频在线| 欧美精品偷拍| 日韩一区二区精品视频| 李宗瑞91在线正在播放| 欧美美女黄色| 亚洲国产成人久久| 国产大尺度视频| 日韩国产在线不卡视频| 69堂亚洲精品首页| 亚洲成人天堂网| 亚洲成av在线| 欧美三级三级三级爽爽爽| 无码aⅴ精品一区二区三区浪潮 | 国产成人综合av| 天天操天天爽天天干| 影音先锋久久资源网| 欧美成人免费在线视频| 亚洲av无码一区二区三区在线| 日韩一区二区在线免费| 在线成人中文字幕| 一区二区三区伦理片| 亚州av日韩av| 亚洲欧洲成视频免费观看| 特大黑人巨人吊xxxx| 四虎5151久久欧美毛片| 精品小视频在线| 好吊视频在线观看| 精品国产中文字幕第一页| 在线播放国产一区二区三区| 天天舔天天操天天干| 日韩理论电影| 久久激情视频免费观看| 欧美成人免费看| 亚洲人成久久| 日韩av免费网站| 中文字幕一区二区三区波野结 | 在线观看免费的av| 欧洲亚洲精品| 日韩片之四级片| 国产真实乱人偷精品| 久久不卡国产精品一区二区| 永久免费看mv网站入口亚洲| www欧美com| 99精品国产在热久久| 日本精品久久电影| 亚洲香蕉在线视频| 懂色av中文一区二区三区| 国产自产在线视频一区| 国产午夜视频在线观看| 亚洲欧洲日产国产综合网| 国产乱人伦精品一区二区三区| 77thz桃花论族在线观看| 色偷偷88欧美精品久久久| 久久精品免费网站| 亚洲高清999| 日韩精品一区二区三区第95| 国产探花视频在线播放| 欧美视频福利| 国产精品video| www天堂在线| 久久精品人人爽人人爽| 国产 欧美 日本| 波多视频一区| 日韩视频免费直播| av黄色免费网站| 黄色精品网站| 国产专区欧美专区| 香蕉国产在线视频| 日韩毛片精品高清免费| 久在线观看视频| 国产精品亚洲综合在线观看| 亚洲欧洲成视频免费观看| avove在线播放| 日韩主播视频在线| 精品一区二区视频| 成人黄色网址| 欧美性猛交一区二区三区精品| 又色又爽又黄18网站| 日韩欧美综合| 欧洲中文字幕国产精品| www.黄色国产| 国产精品不卡在线| 青青在线视频观看| 丁香五月缴情综合网| 色噜噜久久综合伊人一本| 999这里只有精品| 国产成人在线看| 一级做a爰片久久| 校园春色亚洲色图| 日韩精品视频在线| 久久久久成人片免费观看蜜芽| 奇米色一区二区| 欧美另类高清视频在线| caoporn-草棚在线视频最| 欧美巨大另类极品videosbest| 性欧美13一14内谢| 国产免费成人| 精品在线观看一区二区| 久久免费电影| 亚洲成人av中文字幕| 丝袜 亚洲 另类 欧美 重口| 另类小说视频一区二区| 日本一区美女| 99re66热这里只有精品4| 日韩大片在线观看视频| 欧美成人aaaaⅴ片在线看| 高清不卡在线观看av| 97久久国产亚洲精品超碰热| 亚洲国产aⅴ精品一区二区| 久热精品视频在线| 国产av无码专区亚洲av麻豆| 国产精品久久久久久久久免费相片 | 中文字幕制服丝袜| 国内精品美女在线观看| 99久久久久国产精品免费| bestiality新另类大全| 在线成人小视频| 成人高潮免费视频| 国产一区二区三区视频在线播放| 国产麻豆电影在线观看| 欧美电影在线观看一区| 欧美大片免费观看| 俄罗斯嫩小性bbwbbw| 亚洲国产成人av网| 亚洲第一黄色网址| 久久在线精品| 亚洲精品国产一区| 99精品美女视频在线观看热舞| 欧美成人手机在线| 成人毛片视频免费看| 亚洲mv大片欧洲mv大片精品| 亚洲av综合一区二区| 日韩电影免费一区| 性欧美18一19内谢| 91综合久久爱com| 欧美在线视频免费| 在线观看黄av| 日韩午夜在线播放| 亚洲黄色三级视频| 国产日本亚洲高清| 日韩av片网站| 欧美精品1区| 久久精品国产理论片免费| 你懂得影院夜精品a| 久久精品99久久香蕉国产色戒| 亚洲av综合色区无码一二三区 | 精品国产导航| 国产精品91免费在线| www视频在线免费观看| 亚洲丁香久久久| 无码人妻aⅴ一区二区三区有奶水| 国产精品网曝门| 久久久久久久久久影视| 日韩中文字幕麻豆| 国产欧美久久久久| 国产91精品对白在线播放| 91精品视频观看| 超碰激情在线| 久久久999国产| 色综合成人av| 91精品国产福利在线观看| 中国一级免费毛片| 18欧美亚洲精品| 中文字幕丰满乱子伦无码专区| 美女视频黄a大片欧美| 激情五月婷婷六月| 四虎国产精品免费观看| 精品国产乱码久久久久久郑州公司| 国产精品亚洲d| 91精品国产沙发| 二区三区在线观看| 亚洲精品一区二区三区婷婷月| 国产精品爽爽久久久久久| 欧美午夜视频在线观看| 久艹视频在线观看| 国产精品久久夜| 亚洲午夜久久久久久久久红桃| 国产乱码精品1区2区3区| 国语对白做受xxxxx在线中国| 中文在线日韩| 亚洲午夜精品久久久中文影院av | 成人av在线播放网址| 免费在线观看污网站| 视频一区视频二区中文| 天天夜碰日日摸日日澡性色av| 91成人国产| 亚洲乱码国产乱码精品天美传媒| 日韩美女毛片| 国产女人水真多18毛片18精品| 国产精品一区二区美女视频免费看| 国产精品69久久久久| 欧美91看片特黄aaaa| 国外成人在线播放| 国内老司机av在线| 久久在线观看视频| 日韩免费网站| 中文字幕亚洲一区二区三区五十路| 性xxxx视频| 亚洲黄色av女优在线观看| 亚洲国产成人一区二区| 欧美久久高跟鞋激| 在线观看不卡的av| 欧美性受xxxx黑人xyx| 欧美一区免费看| 日本精品一区二区三区高清 | 欧美日韩免费不卡视频一区二区三区| 中文字幕超碰在线| 欧美午夜激情小视频| 久久久午夜影院| 日韩欧美999| 黄色片视频免费| 欧洲av一区二区嗯嗯嗯啊| 在线观看污污网站| 在线观看三级视频欧美| 波多野结衣一二区| 欧美私模裸体表演在线观看| 中文字幕精品无码亚| 欧美网站大全在线观看| 91av国产精品| 91精品在线一区二区| 国产av一区二区三区| 日韩欧美国产一区二区三区| 性一交一乱一精一晶| 亚洲成色999久久网站| 手机看片福利在线| 国产视频综合在线| 成人在线观看免费| 久久久精品亚洲| 深夜国产在线播放| 欧美国产精品人人做人人爱| 18video性欧美19sex高清| 欧美激情亚洲另类| 亚洲校园激情春色| 国产免费亚洲高清| 香港久久久电影| 久久久福利视频| 日韩精品水蜜桃| www.日本三级| 亚洲尤物影院| 国产成年人视频网站| 国产99久久久国产精品潘金 | 国产裸体无遮挡| 精品国产乱码91久久久久久网站| 手机福利小视频在线播放| 伊人青青综合网站| 伊人在我在线看导航| 午夜欧美不卡精品aaaaa| 亚洲黄色中文字幕| 国产精品视频在线播放| 精品国产亚洲一区二区在线观看| 国产一区二区不卡视频| 国产尤物久久久| 欧美爱爱视频网站| 宅男噜噜噜66国产日韩在线观看| 福利在线一区二区三区| 国产成人综合亚洲91猫咪| mm131美女视频| 亚洲蜜臀av乱码久久精品蜜桃| 国产亚洲精品成人| 在线观看不卡一区| 亚洲精品国产av| 一区二区成人精品| heyzo在线播放| 成人免费淫片视频软件| 欧美三级电影在线| 99热都是精品| 日韩成人一区二区三区在线观看| 日本黄色大片在线观看| 亚洲国产精品ⅴa在线观看| 国产无码精品一区二区| 精品视频1区2区| 三级黄视频在线观看| 欧美床上激情在线观看| av成人亚洲| 欧美精品欧美精品| 黄色成人在线网站| 91热视频在线观看| 中文字幕的久久| 精品国产xxx| 精品美女一区二区| 国产精品实拍| 国产精品一区二区三区毛片淫片 | 亚洲电影天堂av| 免费观看在线黄色网| 日本在线观看天堂男亚洲| 成人动漫视频| 成年丰满熟妇午夜免费视频 | av在线中文| 51视频国产精品一区二区| 国产成人澳门| 成人在线视频一区二区三区| 久久国产精品99精品国产| 性欧美精品男男| 色美美综合视频| 人成在线免费视频| 91国产精品电影| 成午夜精品一区二区三区软件| 国产在线无码精品| 国产一区二区0| 91日韩中文字幕| 日韩三级在线观看| 宅男网站在线免费观看| 91九色蝌蚪国产| 9191国语精品高清在线| 中文字幕在线视频一区二区三区 | 精品亚洲精品福利线在观看| 91福利在线免费| 国产精选一区二区| 日韩一级在线| 国产精品久久不卡| 精品久久久久久国产91| 同心难改在线观看| 日本精品免费观看| 欧美在线免费看视频| 一区二区成人网| 国产精品色婷婷| 91丨porny丨在线中文| 久久精品中文字幕免费mv| 人人玩人人添人人澡欧美| 中文字幕欧美日韩一区二区| 久久99精品网久久| 一区二区视频免费看| 欧美大胆人体bbbb| 高清毛片在线观看| 欧美日韩在线播放一区二区| 狂野欧美一区| 日本二区三区视频| 日韩一区二区电影在线| 欧美寡妇性猛交xxx免费| 精品亚洲一区二区三区四区五区高| 美女精品在线| 色偷偷www8888| 日韩免费电影一区| 女厕盗摄一区二区三区| 日韩视频在线播放| 国产一区日韩二区欧美三区| 国产一级一片免费播放| 亚洲男人天堂久| 中文字幕成人| 婷婷五月综合缴情在线视频| 久久色成人在线| 一级全黄裸体免费视频| 欧美激情在线狂野欧美精品| 婷婷成人综合| 五月激情婷婷在线| 午夜欧美在线一二页| 国产经典自拍视频在线观看| 91中文字幕在线| 国产欧美欧美| 日本青青草视频| 亚洲精品天天看| 国产日韩在线观看视频| 亚洲熟妇无码另类久久久| 亚洲国产精品黑人久久久| 亚洲卡一卡二卡三| 国产精品美女免费视频| 黄色工厂这里只有精品| 国产又粗又黄又猛| 精品国产乱码久久久久久影片| 人人鲁人人莫人人爱精品| 日本一二三区视频在线| 久久久精品国产免大香伊| 国产夫妻在线观看| 国产成一区二区| 99视频一区| 国产1区2区3区4区| 曰本色欧美视频在线|