Async Components 非同步我是知道這個東西!
是讓加載組件的時候可以非同步,改善用戶體驗吧~?
這裡應該不包含資料的非同步加載吧!?~
在大型應用中,我們可能需要將應用劃分為較小的部分,並且僅在需要時從伺服器加載組件。為了實現這一點,Vue 提供了 defineAsyncComponent
函數:
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() => {
return new Promise((resolve, reject) => {
// ...從伺服器加載組件
resolve(/* 加載的組件 */)
})
})
// ...像正常組件一樣使用 `AsyncComp`
如你所見,defineAsyncComponent
接受一個加載函數,該函數返回一個 Promise。當你從伺服器獲取到組件定義時,應該調用 Promise 的 resolve
回調。如果加載失敗,也可以調用 reject(reason)
來指示加載失敗。
ES 模塊的動態導入也會返回一個 Promise,因此大多數情況下,我們會將它與 defineAsyncComponent
結合使用。像 Vite 和 webpack 這樣的打包工具也支持該語法(並會將其作為捆綁分割點),因此我們可以用它來導入 Vue 單文件組件(SFC):
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() =>
import('./components/MyComponent.vue')
)
結果的 AsyncComp
是一個包裝組件,只有在實際渲染在頁面上時才會調用加載函數。此外,它會將任何屬性和插槽傳遞給內部組件,因此你可以使用這個非同步包裝器無縫地替換原始組件,同時實現延遲加載。
與普通組件一樣,可以使用 app.component()
全局註冊非同步組件:
app.component('MyComponent', defineAsyncComponent(() =>
import('./components/MyComponent.vue')
))
也可以直接在其父組件內部定義:
<script setup>
import { defineAsyncComponent } from 'vue'
const AdminPage = defineAsyncComponent(() =>
import('./components/AdminPageComponent.vue')
)
</script>
<template>
<AdminPage />
</template>
Promise 是 JavaScript 中的一個對象,用於表示一個異步操作的最終完成(或失敗)及其結果值。簡單來說,Promise 可以讓你在執行異步操作時更方便地處理結果,尤其是在處理異步請求時(如 AJAX 請求)。
Promise 具有三種狀態:
以下是一個使用 Promise 的簡單範例:
const myPromise = new Promise((resolve, reject) => {
// 假設這是一個異步操作,例如 AJAX 請求
const success = true; // 模擬操作成功或失敗的標誌
if (success) {
resolve("操作成功!"); // 異步操作成功,調用 resolve
} else {
reject("操作失敗!"); // 異步操作失敗,調用 reject
}
});
// 使用 then() 處理已解決的狀態,catch() 處理已拒絕的狀態
myPromise
.then(result => {
console.log(result); // 輸出: 操作成功!
})
.catch(error => {
console.error(error); // 如果失敗,輸出錯誤原因
});
Promise 允許鏈式調用,即在一個 Promise 完成後可以再返回一個新的 Promise,這樣可以方便地處理多個異步操作。例如:
fetch('https://api.example.com/data')
.then(response => response.json()) // 將 response 轉換為 JSON
.then(data => {
console.log(data); // 使用獲取到的數據
})
.catch(error => {
console.error('發生錯誤:', error); // 處理錯誤
});
這段程式碼實際上是使用 fetch
API,它本身就會返回一個 Promise 物件。這裡是 Promise 的運作方式的具體說明:
fetch
函數fetch
函數用於發送網絡請求,它會返回一個 Promise。這個 Promise 代表請求的狀態,會在請求完成後進行解決(resolve)或拒絕(reject)。
Promise 使得處理異步操作更加簡潔和可讀,尤其是在需要執行多個連續的異步操作時。使用 Promise 可以避免回調地獄(callback hell)現象,使代碼更易於維護和理解。
非同步操作必然涉及加載和錯誤狀態——defineAsyncComponent()
支持通過高級選項處理這些狀態:
const AsyncComp = defineAsyncComponent({
// 加載函數
loader: () => import('./Foo.vue'),
// 加載非同步組件時使用的組件
loadingComponent: LoadingComponent,
// 顯示加載組件的延遲。默認:200ms。
delay: 200,
// 加載失敗時使用的組件
errorComponent: ErrorComponent,
// 如果提供並超過超時,將顯示錯誤組件。默認:Infinity。
timeout: 3000
})
如果提供了加載組件,則在內部組件加載時會首先顯示它。顯示加載組件之前會有一個默認的 200 毫秒延遲,這是因為在快速網絡下,瞬時的加載狀態可能會被替換得太快,最終看起來像是閃爍。
如果提供了錯誤組件,當加載函數返回的 Promise 被拒絕時,它會顯示。如果請求花費的時間過長,你還可以指定超時,以顯示錯誤組件。
水合(Hydration) 是一個在伺服器端渲染(Server-Side Rendering, SSR)應用程式中使用的概念,特別是在像 Vue.js 和 React 這樣的框架中。這個過程涉及將伺服器生成的靜態 HTML 轉換為可互動的客戶端應用程式。
這部分僅適用於使用伺服器端渲染的情況。
在 Vue 3.5+ 中,非同步組件可以通過提供水合策略來控制何時水合。
Vue 提供了多種內建水合策略。這些內建策略需要單獨導入,以便在未使用時進行樹搖(tree-shaking)。
設計上是故意低層次的,以提高靈活性。將來可以在核心或更高層次的解決方案(例如 Nuxt)上構建編譯器語法糖。
通過 requestIdleCallback
進行水合:
import { defineAsyncComponent, hydrateOnIdle } from 'vue'
const AsyncComp = defineAsyncComponent({
loader: () => import('./Comp.vue'),
hydrate: hydrateOnIdle(/* 可選地傳入最大超時 */)
})
當元素變得可見時通過 IntersectionObserver
進行水合。
import { defineAsyncComponent, hydrateOnVisible } from 'vue'
const AsyncComp = defineAsyncComponent({
loader: () => import('./Comp.vue'),
hydrate: hydrateOnVisible()
})
可以選擇性地傳入觀察者的選項對象值:
hydrateOnVisible({ rootMargin: '100px' })
當指定的媒體查詢匹配時進行水合。
import { defineAsyncComponent, hydrateOnMediaQuery } from 'vue'
const AsyncComp = defineAsyncComponent({
loader: () => import('./Comp.vue'),
hydrate: hydrateOnMediaQuery('(max-width:500px)')
})
當在組件元素上觸發指定事件時進行水合。觸發水合的事件也會在水合完成後重放。
import { defineAsyncComponent, hydrateOnInteraction } from 'vue'
const AsyncComp = defineAsyncComponent({
loader: () => import('./Comp.vue'),
hydrate: hydrateOnInteraction('click')
})
也可以是多個事件類型的列表:
hydrateOnInteraction(['wheel', 'mouseover'])
import { defineAsyncComponent, type HydrationStrategy } from 'vue'
const myStrategy: HydrationStrategy = (hydrate, forEachElement) => {
// forEachElement 是一個幫助函數,用於迭代組件的非水合 DOM 中的所有根元素,
// 因為根元素可以是片段而不是單一元素
forEachElement(el => {
// ...
})
// 準備好後調用 `hydrate`
hydrate()
return () => {
// 如果需要,返回一個清理函數
}
}
const AsyncComp = defineAsyncComponent({
loader: () => import('./Comp.vue'),
hydrate: myStrategy
})
非同步組件可以與 <Suspense>
內建組件一起使用。<Suspense>
和非同步組件之間的交互已在專門的 <Suspense>
章節中記錄。
Suspense 是 Vue 3 中引入的一個功能,用於處理異步組件的加載狀態。它允許開發者更輕鬆地管理異步組件在加載過程中的顯示效果,例如在組件尚未加載完成時顯示一個加載指示器或佔位符。
<Suspense>
組件中,這樣可以控制當這些異步組件加載時的顯示內容。<Suspense>
提供了兩個 slot:以下是一個使用 Suspense
的範例:
<template>
<Suspense>
<template #default>
<AsyncComponent />
</template>
<template #fallback>
<LoadingSpinner /> <!-- 加載時顯示的內容 -->
</template>
</Suspense>
</template>
<script setup>
import AsyncComponent from './AsyncComponent.vue'
import LoadingSpinner from './LoadingSpinner.vue'
</script>
在這個例子中,當 AsyncComponent
正在加載時,<LoadingSpinner />
將顯示在畫面上。一旦 AsyncComponent
加載完成,<AsyncComponent />
將取代加載指示器顯示。
Suspense
是 Vue 3 提供的一個強大功能,旨在簡化異步組件的管理和顯示。它可以提升用戶體驗,讓開發者更方便地處理異步加載時的狀態和顯示效果。
使用 伺服器端渲染(SSR, Server-Side Rendering) 有多個優點,特別是在構建現代化的網頁應用程式時。以下是一些使用 SSR 的原因:
SSR 提供了更好的性能、SEO 和用戶體驗,使其成為構建現代網頁應用程式的一個非常有效的解決方案。然而,實現 SSR 也需要考慮一些挑戰,例如伺服器負載和複雜的開發過程,因此在選擇使用 SSR 時需要根據具體需求進行評估。
這章節有些JS沒學好的觀念一起補齊,
這樣才能對框架的非同步能有更深的理解www~
文章中很多Q的話~就是我個人的疑問,
盡量找好理解的資訊放上去了,難道大家都這麼清楚嗎?
Vue + Nuxt.js = SSR