Suspense技術起初是爲了加載異步組件,但逐漸應用到了全部異步過程當中。其中,異步請求是Suspense最主要的使用場景。在不遠的未來(React17/Vue3.1),基於Suspense的開發模式將成爲主流,同時用戶體驗也會隨着Suspense的使用獲得優化。html
codesandbox.io/s/bold-cdn-…
node
codesandbox.io/s/kind-swar…
react
Suspense做爲一個通用的技術,React和Vue在實現的思路上基本一致,核心原理有兩方面:通訊和渲染。promise
通訊是指:Suspense與嵌入其內部的組件之間的通訊,即Suspense如何獲取組件的異步狀態性能優化
渲染是指:Suspense如何控制嵌入其內部的組件的渲染bash
結論:經過「隱式」的獲取組件異步狀態所關聯的promise。網絡
表面上看來,不論是Vue仍是React,咱們都沒有給Suspense傳任何promise相關的props,那麼Suspense究竟是如何拿到的呢?咱們固化的思惟容易認爲:props是通往組件的惟一入口。架構
實際上,Suspense做爲一個框架內置的組件,它有「充分的自由」去獲取任何運行時中存在的變量。併發
對於Vue來講,若是在setup中"return"了一個promise,那麼Vue就能拿到這個promise,並自動傳遞給離這個組件最近的那個Suspense。框架
對於React來講,若是在render中"throw"了一個promise,那麼React就能捕獲到這個promise,並自動傳遞給離這個組件最近的那個Suspense。
這樣,Suspense就能獲取到組件的異步狀態了。
結論:預渲染嵌入的組件到一個隱藏的dom容器中,並在異步狀態resolve以後把預渲染的組件移動到真實的dom容器中。
Suspense總會預渲染組件到一個隱藏的容器,以後它會根據所關聯的promise的狀態進行抉擇:
若是promise處於pending狀態,那麼就會渲染fallback組件到真實的dom容器中
若是promise到達resolve狀態,那麼就會直接把預渲染好的組件移動到真實的dom容器中,並清除fallback組件
若是promise到達reject狀態,那麼框架會直接拋出reject的錯誤,後面能夠被ErrorBoundary接收
在組件中加載異步數據是業務場景中最多見的需求,組件的狀態會根據異步數據的狀態不一樣而變化,一般是:loading狀態 -> 真實內容。
使用傳統的v-if/v-else,或者jsx中的三元表達式的形式,去渲染不一樣狀態下對應的組件內容,實際會有性能問題:
// template
<Loading v-if="loading">loading...</Loading>
<Content v-else>真實內容</Content>
// jsx
(
loading ? <Loading>loading</Loading> : <Content>真實內容</Content>
)複製代碼
在切換渲染兩種不一樣的element時,都伴隨着組件的銷燬與重建。而若是使用Suspense,真實內容和fallback這二者會同時存在,真實內容不會隨着fallback出現而銷燬,也不會隨着fallback的消失而重建,相反真實內容只是在更新。
這樣,用戶體驗就獲得了第一階段的優化,由於頁面的渲染性能明顯提高。
渲染性能已經獲得明顯的提高,那麼咱們還能優化什麼呢?React併發模式帶來了新的思路:幹掉loading狀態。
React併發模式是React Fiber架構的應用,在React Fiber架構下,組件樹的更新以組件爲粒度被異步化,組件的更新能夠被中斷,從而不會阻塞主線程。
更多內容請看:reactjs.org/docs/concur…
實際環境中,用戶的設備性能、網絡速度各有不一樣,有的人性能好網速快,有的人性能差網速慢,結果就致使這種狀況:
設備條件 |
使用體驗 |
緣由 |
---|---|---|
高 |
低 |
設備條件已經這麼好了,加載數據毫秒級別,可是仍是要閃一下loading狀態 |
低 |
高 |
設備條件很差,加載數據秒級別,有一個loading狀態會很舒服 |
在React併發模式中結合使用Suspense,便可解決上述問題,這裏有一個demo:
點擊Refresh會更新列表
更新列表的接口耗時隨機在0-1s之間
若是接口返回的時間在0.5s以內,則不會顯示loading狀態
若是接口返回的時間在0.5s以外,則會顯示loading狀態
是的,咱們徹底能夠自行實現這個功能,無非是加一個定時器,只有超過某個時間後,纔會顯示loading。可是,這樣咱們就享受不到Suspense預渲染帶來的性能提高了。
雖然Vue在Suspense上沒法貢獻更多性能優化,可是Vue會從另一個方向:預分析vnode,根據類型不一樣給予相應的patchFlag,並根據flag的不一樣採起最高效的更新方式,帶來顯著的渲染性能提高。