新聞中心
Suspense 不是你想的那樣。是的,它幫助我們處理異步組件,但它的作用遠(yuǎn)不止于此。

Suspense 允許我們協(xié)調(diào)整個(gè)應(yīng)用程序的加載狀態(tài),包括所有深度嵌套的組件。而不是像一個(gè)爆米花用戶界面一樣,到處都是 loading,組件突然奔的一下到位。
有了 Suspense, 我們可以有一個(gè)單一的、有組織的系統(tǒng),一次性加載所有東西。
而且,Suspense 也給我們提供了細(xì)粒度的控制,所以如果需要的話,我們可以在兩者之間實(shí)現(xiàn)一些東西。
在這篇文章中,我們將學(xué)到很多關(guān)于 Suspense 的知識(shí)--它是什么,能干什么,以及如何使用它。
首先,我們將仔細(xì)看看這些爆米花界面。然后,在看看如何使用Suspense來解決這些問題。之后,嘗試通過在整個(gè)應(yīng)用程序中嵌套Suspense來獲得更精細(xì)的控制。最后,簡(jiǎn)單看看如何使用占位符來豐富我們的用戶界面。
爆米花UI-- Suspense 之前
事例地址:https://codesandbox.io/s/uncoordinated-loading-before-suspense-srh8ll?file=/src/App.vue。
如果沒有 Suspense,每個(gè)組件都必須單獨(dú)處理其加載狀態(tài)。
這可能導(dǎo)致一些相當(dāng)糟糕的用戶體驗(yàn),多個(gè)加載按鈕和內(nèi)容突然出現(xiàn)在屏幕上,就像你在制作爆米花一樣。
雖然,我們可以創(chuàng)建抽象組件來處理這些加載狀態(tài),但這比使用Suspense要困難得多。有一個(gè)單一的點(diǎn)來管理加載狀態(tài),比每個(gè)組件做自己的事情要容易維護(hù)得多。
在事例中,我們使用BeforeSuspense組件來模擬一個(gè)內(nèi)部處理加載狀態(tài)的組件。把它命名為BeforeSuspense,因?yàn)橐坏┪覀儗?shí)現(xiàn)了Suspense,我們就會(huì)把它重構(gòu)為WithSuspense組件。
BeforeSuspense.vue
一開始設(shè)置 loading 為 true,所以顯示 Spinner 組件。然后,當(dāng)setTimeout完成后,將 loading 設(shè)置為 false,隱藏 Spinner 并使組件的背景為綠色。
在這個(gè)組件中,還包括一個(gè) slot ,這樣其它組件就可以套在 BeforeSuspense 組件中了:
沒有什么太花哨的東西。只是一些嵌套的組件,有不同的時(shí)間值傳遞給它們。
下面,我們來看看怎么通過使用 Suspense 組件來改進(jìn)這個(gè)爆米花用戶界面。
Suspense
事例地址:https://codesandbox.io/s/coordinated-loading-with-suspense-b6dcbi?file=/src/App.vue。
現(xiàn)在,我們使用Suspense來處理這些亂七八糟的東西,并將其變成一個(gè)更好的用戶體驗(yàn)。
不過,首先我們需要快速了解一下Suspense到底是什么?
Suspense 基礎(chǔ)知識(shí)
以下是 Suspense 部分的基本結(jié)構(gòu):
為了使用Suspense,把異步組件放入 default 槽,把回退加載狀態(tài)放入 fallback 槽。
異步組件是以下兩種情況之一:
- 一個(gè)帶有async setup?函數(shù)的組件,該組件返回一個(gè)Promise,或者在script setup?中使用頂級(jí)await。
- 使用defineAsyncComponent 異步加載的組件。
無論哪種方式,我們最終都會(huì)得到一個(gè)開始未解決 的 Promise ,然后最終得到解決。
當(dāng)該 Promise 未被解決時(shí),Suspense 組件將顯示 fallback 槽中的內(nèi)容。然后,當(dāng)Promise 被解決時(shí),它會(huì)在 default 槽中顯示該異步組件。
注意: 這里沒有錯(cuò)誤處理路基。起初我以為有,但這是對(duì)懸念的一個(gè)常見誤解。如果想知道是什么導(dǎo)致了錯(cuò)誤??梢允褂胦nErrorCaptured鉤子來捕捉錯(cuò)誤,但這是一個(gè)獨(dú)立于Suspense的功能。
現(xiàn)在我們對(duì)Suspense有了一些了解,讓我們回到我們的演示應(yīng)用程序。
管理異步依賴關(guān)系
為了讓Suspense管理我們的加載狀態(tài),首先需要將BeforeSuspense組件轉(zhuǎn)換成一個(gè)異步組件。
我們將它命名為 WithSuspense,內(nèi)容如下:
我們已經(jīng)完全刪除了加載狀態(tài)的Spinner,因?yàn)檫@個(gè)組件不再有加載狀態(tài)了。
因?yàn)檫@是一個(gè)異步組件,setup 函數(shù)直到它完成加載才會(huì)返回。該組件只有在 setup 函數(shù)完成后才會(huì)被加載。因此,與BeforeSuspense組件不同,WithSuspense組件內(nèi)容在加載完畢之前不會(huì)被渲染。
這對(duì)任何異步組件來說都是如此,不管它是如何被使用的。在setup函數(shù)返回(如果是同步的)或解析(如果是異步的)之前,它不會(huì)渲染任何東西。
有了WithSuspense組件,我們?nèi)匀恍枰貥?gòu)我們的App?組件,以便在Suspense組件中使用這個(gè)組件。
結(jié)構(gòu)和之前一樣,但這次是在 Suspense 組件的默認(rèn)槽中。我們還加入了 fallback 槽,在加載時(shí)渲染我們的Spinner組件。
在演示中,你會(huì)看到它顯示加載按鈕,直到所有的組件都加載完畢。只有在那時(shí),它才會(huì)顯示現(xiàn)在完全加載的組件樹。
異步瀑布
如果你仔細(xì)注意,你會(huì)注意到這些組件并不像你想象的那樣是并聯(lián)加載的。
總的加載時(shí)間不是基于最慢的組件(5秒)。相反,這個(gè)時(shí)間要長(zhǎng)得多。這是因?yàn)閂ue只有在父異步組件完全解析后才會(huì)開始加載子組件。
你可以通過把日志放到WithSuspense組件中來測(cè)試這一點(diǎn)。一個(gè)在安裝開始跟蹤安裝,一個(gè)在我們調(diào)用解決之前。
最初使用BeforeSuspense組件的例子中,整個(gè)組件樹被掛載,無需等待,所有的 "異步 "操作都是并行啟動(dòng)的。這意味著Suspense有可能通過引入這種異步瀑布而影響性能。所以請(qǐng)記住這一點(diǎn)。
嵌套 Suspense 以隔離子樹
事例地址:https://codesandbox.io/s/nesting-suspense-wt0q7k?file=/src/App.vue。
這里有一個(gè)深度嵌套的組件,它需要整整5秒來加載,阻塞了整個(gè)UI,盡管大多數(shù)組件加載完成的時(shí)間要早得多。
但對(duì)我們來說有一個(gè)解決方案。
通過進(jìn)一步嵌套第二個(gè)Suspense組件,我們可以在等待這個(gè)組件完成加載時(shí)顯示應(yīng)用程序的其他部分。
將其包裹在第二個(gè)Suspense組件中,使其與應(yīng)用程序的其他部分隔離。Suspense組件本身是一個(gè)同步組件,所以當(dāng)它的父級(jí)組件被加載時(shí),它就會(huì)被加載。
然后它將顯示它自己的 fallback 內(nèi)容,直到5秒結(jié)束。
通過這樣做,我們可以隔離應(yīng)用程序中加載較慢的部分,減少我們的首次交互時(shí)間。在某些情況下,這可能是必要的,特別是當(dāng)你需要避免異步瀑布時(shí)。
從功能的角度來看,這也是有意義的。你的應(yīng)用程序的每個(gè)功能或 "部分"都可以被包裹在它自己的??Suspense??組件中,所以每個(gè)功能的加載都是一個(gè)單一的邏輯單元。
當(dāng)然,如果你用 "Suspense" 包裝每一個(gè)組成部分,我們就會(huì)回到我們開始的地方。我們可以選擇以任何最合理的方式來批處理我們的加載狀態(tài)。
使用占位符的 Suspense
事例地址:https://codesandbox.io/s/placeholders-and-suspense-k5uzw0?
與其使用單一的 spinner,占位符組件往往可以提供更好的體驗(yàn)。
這種方式向用戶展示將要展示的內(nèi)容,并讓他們?cè)诮缑驿秩厩坝幸环N期待的感覺。這是 spinner 無法做到的。
可以說--它們很時(shí)髦,看起來很酷。因此,我們重構(gòu)代碼,使用占位符方式:
我們安排了這些Placeholder組件,并對(duì)它們進(jìn)行了風(fēng)格化處理,使它們看起來與WithSuspense組件完全一樣。這提供了一個(gè)在加載和裝載狀態(tài)之間的無縫過渡。
在演示中,Placeholder組件在背景上給我們提供了一個(gè)CSS動(dòng)畫,以創(chuàng)造一個(gè)脈動(dòng)的效果:
.fast-gradient {
background: linear-gradient(
to right,
rgba(255, 255, 255, 0.1),
rgba(255, 255, 255, 0.4)
);
background-size: 200% 200%;
animation: gradient 2s ease-in-out infinite;
}
@keyframes gradient {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
總結(jié)
爆米花的加載狀態(tài)是非常明顯的,會(huì)傷害用戶體驗(yàn)。
幸運(yùn)的是,Suspense 是一個(gè)很棒的新特性,它為我們?cè)赩ue應(yīng)用程序中協(xié)調(diào)加載狀態(tài)提供了很多選擇。
然而,在寫這篇文章的時(shí)候,Suspense仍然被認(rèn)為是實(shí)驗(yàn)性的,所以要謹(jǐn)慎行事。關(guān)于它的狀態(tài)的最新信息,請(qǐng)參考文檔。
分享題目:Vue3中還處在實(shí)驗(yàn)性階段Suspense是個(gè)啥?
文章出自:http://www.5511xx.com/article/dpehesj.html


咨詢
建站咨詢
