可恢復性與水合
Qwik 應用程式的一個關鍵概念是它們可以從伺服器端渲染狀態恢復。解釋可恢復性的最佳方法是了解當前這一代框架是如何可重播的(水合)。
當 SSR/SSG 應用程式在客戶端啟動時,它需要客戶端上的框架恢復三項資訊
- 監聽器 - 定位事件監聽器並將它們安裝在 DOM 節點上,使應用程式具有互動性。
- 元件樹 - 建立一個表示應用程式元件樹的內部資料結構。
- 應用程式狀態 - 還原在伺服器上
store
中提取或儲存的任何資料。
總體而言,這稱為「注水」。目前所有世代的框架都需要這個步驟來使應用程式具有互動性。
注水成本很高,原因有兩個
- 框架必須下載與目前頁面相關聯的所有元件程式碼。
- 框架必須執行與頁面上元件相關聯的範本,以重建監聽器位置和內部元件樹。
Qwik 的不同之處在於,它不需要注水即可在客戶端恢復應用程式。不需要注水是 Qwik 應用程式啟動速度極快的原因。
所有其他框架的注水都會在客戶端上 **重播** 所有應用程式邏輯。而 Qwik 則會在伺服器上暫停執行,並在客戶端上繼續執行。
介紹可恢復性
可恢復性是指在伺服器上暫停執行並在客戶端上繼續執行,而無需重播和下載所有應用程式邏輯。
一個很好的心智模型是,Qwik 應用程式在其生命週期的任何時間點都可以被序列化並移動到不同的虛擬機器實例(伺服器到瀏覽器)。在那裡,應用程式只需從序列化停止的地方繼續執行。不需要注水。因此,Qwik 應用程式不會注水;它們會恢復。
為了實現這一點,Qwik 需要以與無程式碼啟動相容的方式解決這 3 個問題(監聽器、元件樹、應用程式狀態)。
監聽器
沒有事件監聽器的 DOM 只是一個靜態頁面;它不是一個應用程式。現今所有網站的標準都是高度互動性,因此即使是看起來最靜態的網站也充滿了事件監聽器。這些包括選單、懸停、展開詳細資訊,甚至是完整的互動式應用程式。
現有框架通過下載元件並執行其範本來解決事件監聽器問題,以收集事件監聽器,然後將其附加到 DOM。目前的方法存在以下問題
- 需要急切地下載範本程式碼。
- 需要急切地執行範本程式碼。
- 需要急切地下載事件處理常式程式碼(以便附加)。
上述方法不具備可擴展性。隨著應用程式變得越來越複雜,需要急切下載和執行的程式碼量會隨著應用程式的大小成比例增長。這會對應用程式啟動效能產生負面影響,進而影響使用者體驗。在其他框架中,延遲載入應用程式的區塊本身就成為一項開發任務,需要耗費時間和精力。在 Qwik 中,延遲載入是可恢復架構的自然結果。
Qwik 通過將事件監聽器序列化到 DOM 中來解決上述問題,如下所示
<button on:click="./chunk.js#handler_symbol">click me</button>
Qwik 仍然需要收集監聽器資訊,但此步驟作為 SSR/SSG 的一部分完成。然後將 SSR/SSG 的結果序列化為 HTML,以便瀏覽器無需執行任何操作即可繼續執行。請注意,on:click
屬性包含在不急切執行任何操作的情況下繼續執行應用程式所需的所有資訊。
- Qwikloader 設置一個全局監聽器,而不是每個 DOM 元素設置多個單獨的監聽器。此步驟可以在沒有應用程式程式碼的情況下完成。
- HTML 包含指向區塊和符號名稱的 URL。該屬性會告訴 Qwikloader 要下載哪個程式碼區塊以及要從區塊中擷取哪個符號,然後執行。
- 最後,為了讓上述所有功能成為可能,Qwik 的事件處理實作理解非同步性,這使其能夠自動延遲載入閉包。
元件樹
框架與元件樹一起使用。為此,框架需要完全理解元件樹,才能知道哪些元件需要重新渲染以及何時重新渲染。如果您查看現有的框架 SSR/SSG 輸出,則元件邊界資訊已被破壞。通過查看生成的 HTML 無法知道元件邊界在哪裡。為了重新創建此資訊,框架會重新執行元件模板並記憶元件邊界位置。重新執行就是水合作用。水合作用的成本很高,因為它需要下載元件模板並執行它們。
Qwik 會在 SSR/SSG 的過程中收集 元件邊界資訊,然後將該資訊序列化為 HTML。結果是 Qwik 可以
- 在沒有實際存在元件程式碼的情況下重建元件層次結構資訊。元件程式碼可以保持延遲載入。
- Qwik 可以僅針對需要重新渲染的元件延遲執行此操作,而不是預先全部執行。
- Qwik 會收集商店和元件之間的關係資訊。這會創建一個訂閱模型,通知 Qwik 由於狀態更改而需要重新渲染哪些元件。訂閱資訊也會被序列化為 HTML。
應用程式狀態
現有的框架通常都有一種將應用程式狀態序列化為 HTML 的方法,以便可以在水合作用的過程中恢復狀態。在這種方式下,它們與 Qwik 非常相似。但是,Qwik 的狀態管理與元件的生命週期更加緊密地集成在一起。實際上,這意味著元件可以獨立於元件的狀態進行延遲載入。這在現有框架中並不容易實現,因為元件屬性通常由父元件創建。這會產生連鎖反應。為了恢復元件 X,也需要恢復其父元件。 Qwik 允許在沒有父元件程式碼的情況下恢復任何元件。
序列化
考慮序列化的最簡單方法是通過 JSON.stringify
。但是,JSON 有幾個限制。 Qwik 可以克服一些限制,但有些則無法克服,它們對開發人員可以做的事情施加了限制。在構建 Qwik 應用程式時,了解這些限制非常重要。
Qwik 解決的 JSON 的限制
- JSON 產生一個 DAG。 DAG 代表有向無環圖,這意味著被序列化的物件不能有循環引用。這是一個很大的限制,因為應用程式狀態通常是循環的。 Qwik 確保在物件圖被序列化時,循環引用會被正確保存然後恢復。
- JSON 無法序列化某些物件類型。例如,DOM 引用或日期。 Qwik 的序列化格式確保可以正確序列化和恢復此類物件。以下是可以用 Qwik 序列化的類型列表
- DOM 引用
- Promises(請參閱 資源)
- 函數閉包(如果包裝在 QRL 中)
- 日期
URL
物件Map
和Set
实例。
Qwik 未解決的 JSON 的限制
對於無法序列化的情況,程式碼應該僅在用戶端執行。
編寫具有可序列化性的應用程式
框架的可恢復性能力也必須擴展到應用程式的可恢復性。這意味著框架必須提供機制,讓開發人員以可序列化然後恢復(無需重新啟動)的方式表達應用程式的*組件*和*實體*。這需要在編寫應用程式時考慮到可恢復性限制。開發人員不可能繼續以堆中心的方式編寫應用程式,並期望更好的框架可以彌補這種次優的方法。
開發人員必須以 DOM 為中心的方式編寫他們的應用程式。這需要改變行為並重新調整網路開發人員的技能。框架需要提供指導和 API,讓開發人員可以輕鬆地以這種方式編寫應用程式。
可恢復性的其他好處
使用可恢復性最明顯的好處是用於伺服器端渲染。但是,還有其他好處
- 序列化現有的 PWA 應用程式,以便用戶在返回應用程式時不會丟失上下文
- 改進渲染效能,因為只需要重新渲染更改的組件
- 細粒度的延遲載入
- 降低記憶體壓力,尤其是在行動裝置上
- 現有靜態網站的漸進式互動性