EP28 - 非同步組件

更新 發佈閱讀 20 分鐘
Async Components 非同步我是知道這個東西!
是讓加載組件的時候可以非同步,改善用戶體驗吧~?
這裡應該不包含資料的非同步加載吧!?~

基本用法 - Basic Usage

在大型應用中,我們可能需要將應用劃分為較小的部分,並且僅在需要時從伺服器加載組件。為了實現這一點,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>

Q: 什麼是Promise?

Promise 是 JavaScript 中的一個對象,用於表示一個異步操作的最終完成(或失敗)及其結果值。簡單來說,Promise 可以讓你在執行異步操作時更方便地處理結果,尤其是在處理異步請求時(如 AJAX 請求)。

Promise 的狀態

Promise 具有三種狀態:

  1. 待定(Pending):初始狀態,既不是成功也不是失敗。
  2. 已解決(Fulfilled):異步操作成功完成,並返回了一個結果。
  3. 已拒絕(Rejected):異步操作失敗,並返回了一個錯誤原因。

使用 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 完成後可以再返回一個新的 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)現象,使代碼更易於維護和理解。

加載和錯誤狀態 - Loading and Error States

非同步操作必然涉及加載和錯誤狀態——defineAsyncComponent() 支持通過高級選項處理這些狀態:

const AsyncComp = defineAsyncComponent({
// 加載函數
loader: () => import('./Foo.vue'),

// 加載非同步組件時使用的組件
loadingComponent: LoadingComponent,
// 顯示加載組件的延遲。默認:200ms。
delay: 200,

// 加載失敗時使用的組件
errorComponent: ErrorComponent,
// 如果提供並超過超時,將顯示錯誤組件。默認:Infinity。
timeout: 3000
})

如果提供了加載組件,則在內部組件加載時會首先顯示它。顯示加載組件之前會有一個默認的 200 毫秒延遲,這是因為在快速網絡下,瞬時的加載狀態可能會被替換得太快,最終看起來像是閃爍。

如果提供了錯誤組件,當加載函數返回的 Promise 被拒絕時,它會顯示。如果請求花費的時間過長,你還可以指定超時,以顯示錯誤組件。

Q: 什麼是Hydration 水合?

水合(Hydration) 是一個在伺服器端渲染(Server-Side Rendering, SSR)應用程式中使用的概念,特別是在像 Vue.js 和 React 這樣的框架中。這個過程涉及將伺服器生成的靜態 HTML 轉換為可互動的客戶端應用程式。

水合的工作流程

  1. 伺服器端渲染:當用戶請求一個頁面時,伺服器生成一個完整的 HTML 頁面並發送給用戶的瀏覽器。這樣用戶可以快速看到內容,而不必等待 JavaScript 完全加載。
  2. 客戶端加載 JavaScript:當瀏覽器接收到 HTML 時,JavaScript 檔案也會被加載。這些 JavaScript 代碼包含了應用程式的邏輯和行為。
  3. 添加互動性:在 JavaScript 加載完成後,框架會將伺服器生成的靜態內容「水合」成可互動的元素。這包括將事件處理器綁定到 DOM 元素,使得用戶可以與應用程式互動。

水合的好處

  • 快速響應時間:用戶可以立即看到頁面內容,而不必等待所有 JavaScript 完全加載。這提高了首次渲染的速度。
  • SEO 友好:伺服器端渲染的頁面對搜尋引擎更友好,因為搜尋引擎可以抓取到靜態 HTML 內容,而不是等待 JavaScript 加載。
  • 增強用戶體驗:用戶在等待 JavaScript 加載時,仍然能夠看到和訪問內容,提供更流暢的體驗。

水合的挑戰

  • 狀態不一致:如果伺服器端渲染的 HTML 和客戶端的 JavaScript 之間存在狀態不一致,可能會導致重水合過程中的錯誤或不正確的顯示。
  • 性能開銷:水合過程會消耗資源,特別是在需要大量 DOM 操作的情況下。

延遲水合 - Lazy Hydration (3.5+)

這部分僅適用於使用伺服器端渲染的情況。

在 Vue 3.5+ 中,非同步組件可以通過提供水合策略來控制何時水合。

Vue 提供了多種內建水合策略。這些內建策略需要單獨導入,以便在未使用時進行樹搖(tree-shaking)。

設計上是故意低層次的,以提高靈活性。將來可以在核心或更高層次的解決方案(例如 Nuxt)上構建編譯器語法糖。

空閒時水合 - Hydrate on Idle

通過 requestIdleCallback 進行水合:

import { defineAsyncComponent, hydrateOnIdle } from 'vue'

const AsyncComp = defineAsyncComponent({
loader: () => import('./Comp.vue'),
hydrate: hydrateOnIdle(/* 可選地傳入最大超時 */)
})

可見時水合 - Hydrate on Visible

當元素變得可見時通過 IntersectionObserver 進行水合。

import { defineAsyncComponent, hydrateOnVisible } from 'vue'

const AsyncComp = defineAsyncComponent({
loader: () => import('./Comp.vue'),
hydrate: hydrateOnVisible()
})

可以選擇性地傳入觀察者的選項對象值:

hydrateOnVisible({ rootMargin: '100px' })

媒體查詢時水合 - Hydrate on Media Query

當指定的媒體查詢匹配時進行水合。

import { defineAsyncComponent, hydrateOnMediaQuery } from 'vue'

const AsyncComp = defineAsyncComponent({
loader: () => import('./Comp.vue'),
hydrate: hydrateOnMediaQuery('(max-width:500px)')
})

交互時水合 - Hydrate on Interaction

當在組件元素上觸發指定事件時進行水合。觸發水合的事件也會在水合完成後重放。

import { defineAsyncComponent, hydrateOnInteraction } from 'vue'

const AsyncComp = defineAsyncComponent({
loader: () => import('./Comp.vue'),
hydrate: hydrateOnInteraction('click')
})

也可以是多個事件類型的列表:

hydrateOnInteraction(['wheel', 'mouseover'])

自定義策略 - Custom Strategy

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 一起使用 - Using with Suspense

非同步組件可以與 <Suspense> 內建組件一起使用。<Suspense> 和非同步組件之間的交互已在專門的 <Suspense> 章節中記錄。

Q: 什麼是Suspense?

Suspense 是 Vue 3 中引入的一個功能,用於處理異步組件的加載狀態。它允許開發者更輕鬆地管理異步組件在加載過程中的顯示效果,例如在組件尚未加載完成時顯示一個加載指示器或佔位符。

Suspense 的工作原理

  1. 包裹異步組件:將一個或多個異步組件包裹在 <Suspense> 組件中,這樣可以控制當這些異步組件加載時的顯示內容。
  2. 使用 slot<Suspense> 提供了兩個 slot:
  • default slot:用於顯示加載完成後的內容。
  • fallback 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 來提供良好的用戶體驗。
  • 多個異步組件:當有多個異步組件需要加載時,可以使用 Suspense 來統一管理它們的加載狀態。

結論

Suspense 是 Vue 3 提供的一個強大功能,旨在簡化異步組件的管理和顯示。它可以提升用戶體驗,讓開發者更方便地處理異步加載時的狀態和顯示效果。

Q: 為什麼要用SSR?

使用 伺服器端渲染(SSR, Server-Side Rendering) 有多個優點,特別是在構建現代化的網頁應用程式時。以下是一些使用 SSR 的原因:

1. 更快的初始加載時間

  • SSR 會在伺服器上預渲染 HTML,這樣用戶在首次加載頁面時可以立即看到內容,而不需要等待 JavaScript 加載和執行完成。這對於用戶體驗尤為重要,特別是在網速較慢的情況下。

2. 更好的 SEO(搜索引擎優化)

  • 搜索引擎的爬蟲在索引網頁內容時通常對 JavaScript 渲染的內容支持不佳。使用 SSR,頁面的 HTML 在伺服器端生成,搜索引擎可以輕易讀取並索引這些內容,從而提高網站的可見性和排名。

3. 改善社交媒體分享

  • 在 SSR 中生成的 HTML 包含完整的內容,這樣當用戶在社交媒體上分享頁面鏈接時,社交平台能夠抓取到正確的預覽信息(例如標題、描述、縮略圖等),提高了分享的效果。

4. 降低客戶端負擔

  • SSR 將大部分渲染工作移至伺服器端,這可以降低客戶端設備(特別是移動設備)的運算負擔,提供更流暢的用戶體驗。

5. 更佳的性能優化

  • SSR 使得在伺服器端進行性能優化變得更加容易,例如使用快取來提高響應速度,這對於需要快速響應的應用特別重要。

6. 支持多種渲染策略

  • 使用 SSR 可以更靈活地支持不同的渲染策略,例如先渲染主要內容,然後再進行其他次要內容的加載。

7. 可擴展性

  • SSR 可以輕鬆地與其他技術堆棧結合使用,例如與 Node.js、Express、Django 等後端框架協作,提供更完整的全棧解決方案。

總結

SSR 提供了更好的性能、SEO 和用戶體驗,使其成為構建現代網頁應用程式的一個非常有效的解決方案。然而,實現 SSR 也需要考慮一些挑戰,例如伺服器負載和複雜的開發過程,因此在選擇使用 SSR 時需要根據具體需求進行評估。

這章節有些JS沒學好的觀念一起補齊,
這樣才能對框架的非同步能有更深的理解www~
文章中很多Q的話~就是我個人的疑問,
盡量找好理解的資訊放上去了,難道大家都這麼清楚嗎?
Vue + Nuxt.js = SSR









留言
avatar-img
卡關的人生
4會員
73內容數
分享生活趣事~
卡關的人生的其他內容
2024/11/10
Vue 提供了多種動畫技術來提升應用程式的互動性,包括基於 CSS 類別的動畫、基於狀態的動畫,以及使用監視器來動畫化數值。基於類別的動畫可通過動態添加 CSS 類別來觸發,像是觸發按鈕搖動效果。基於狀態的動畫則是透過樣式綁定,根據互動動態調整元素的外觀,例如根據滑鼠位置改變背景顏色。
Thumbnail
2024/11/10
Vue 提供了多種動畫技術來提升應用程式的互動性,包括基於 CSS 類別的動畫、基於狀態的動畫,以及使用監視器來動畫化數值。基於類別的動畫可通過動態添加 CSS 類別來觸發,像是觸發按鈕搖動效果。基於狀態的動畫則是透過樣式綁定,根據互動動態調整元素的外觀,例如根據滑鼠位置改變背景顏色。
Thumbnail
2024/11/09
Web Components 是一組網頁原生 API,允許開發者創建可重複使用的自訂元素。Vue 與 Web Components 是互補的技術,Vue 支援整合和創建自訂元素。
Thumbnail
2024/11/09
Web Components 是一組網頁原生 API,允許開發者創建可重複使用的自訂元素。Vue 與 Web Components 是互補的技術,Vue 支援整合和創建自訂元素。
Thumbnail
2024/11/08
Vue 建議使用模板構建應用程式,但在需要 JavaScript 的全程式化功能時,渲染函數可派上用場。渲染函數通過 h() 函數創建 vnode,h 是 hyperscript 的簡寫,能生成 HTML 的 JavaScript。
Thumbnail
2024/11/08
Vue 建議使用模板構建應用程式,但在需要 JavaScript 的全程式化功能時,渲染函數可派上用場。渲染函數通過 h() 函數創建 vnode,h 是 hyperscript 的簡寫,能生成 HTML 的 JavaScript。
Thumbnail
看更多
你可能也想看
Thumbnail
Composition API 是 Vue 3 的一組 API,允許使用導入的函數編寫 Vue 組件,涵蓋反應性 API、生命週期鉤子和依賴注入。它主要在單文件組件的 <script setup> 語法中使用。
Thumbnail
Composition API 是 Vue 3 的一組 API,允許使用導入的函數編寫 Vue 組件,涵蓋反應性 API、生命週期鉤子和依賴注入。它主要在單文件組件的 <script setup> 語法中使用。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
5 月將於臺北表演藝術中心映演的「2026 北藝嚴選」《海妲・蓋柏樂》,由臺灣劇團「晃晃跨幅町」製作,本文將以從舞台符號、聲音與表演調度切入,討論海妲・蓋柏樂在父權社會結構下的困境,並結合榮格心理學與馮.法蘭茲對「阿尼姆斯」與「永恆少年」原型的分析,理解女人何以走向精神性的操控、毀滅與死亡。
Thumbnail
5 月將於臺北表演藝術中心映演的「2026 北藝嚴選」《海妲・蓋柏樂》,由臺灣劇團「晃晃跨幅町」製作,本文將以從舞台符號、聲音與表演調度切入,討論海妲・蓋柏樂在父權社會結構下的困境,並結合榮格心理學與馮.法蘭茲對「阿尼姆斯」與「永恆少年」原型的分析,理解女人何以走向精神性的操控、毀滅與死亡。
Thumbnail
歡迎來到 React 白話文運動第三篇,今天我們將深入探討 JavaScript 中的非同步操作,並介紹兩個重要的關鍵字:Async 與 Await。在這篇文章中,我們將透過實例演示非同步操作的概念,以及如何使用 Promise、Fetch、Async 和 Await 來更有效地處理非同步程式。
Thumbnail
歡迎來到 React 白話文運動第三篇,今天我們將深入探討 JavaScript 中的非同步操作,並介紹兩個重要的關鍵字:Async 與 Await。在這篇文章中,我們將透過實例演示非同步操作的概念,以及如何使用 Promise、Fetch、Async 和 Await 來更有效地處理非同步程式。
Thumbnail
學會了使用 <KeepAlive>,這是一個內建組件,允許我們在動態切換多個組件時有條件地緩存組件實例,避免狀態丟失並提高速度。使用 include 和 exclude 屬性來自定義緩存行為,並透過 max 屬性限制緩存的實例數量。
Thumbnail
學會了使用 <KeepAlive>,這是一個內建組件,允許我們在動態切換多個組件時有條件地緩存組件實例,避免狀態丟失並提高速度。使用 include 和 exclude 屬性來自定義緩存行為,並透過 max 屬性限制緩存的實例數量。
Thumbnail
《轉轉生》(Re:INCARNATION)為奈及利亞編舞家庫德斯.奧尼奎庫與 Q 舞團創作的當代舞蹈作品,結合拉各斯街頭節奏、Afrobeat/Afrobeats、以及約魯巴宇宙觀的非線性時間,建構出關於輪迴的「誕生—死亡—重生」儀式結構。本文將從約魯巴哲學概念出發,解析其去殖民的身體政治。
Thumbnail
《轉轉生》(Re:INCARNATION)為奈及利亞編舞家庫德斯.奧尼奎庫與 Q 舞團創作的當代舞蹈作品,結合拉各斯街頭節奏、Afrobeat/Afrobeats、以及約魯巴宇宙觀的非線性時間,建構出關於輪迴的「誕生—死亡—重生」儀式結構。本文將從約魯巴哲學概念出發,解析其去殖民的身體政治。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
Vue 插件是自包含的代碼,通過 app.use() 方法安裝,用於擴展應用功能。插件可定義為包含 install() 方法的物件,或簡單的函數。插件用途包括註冊全局組件、自定義指令、資源注入和添加全局屬性。
Thumbnail
Vue 插件是自包含的代碼,通過 app.use() 方法安裝,用於擴展應用功能。插件可定義為包含 install() 方法的物件,或簡單的函數。插件用途包括註冊全局組件、自定義指令、資源注入和添加全局屬性。
Thumbnail
這次可以將範例內容轉移到components資料夾中,並在App.vue中引用它們。在App.vue中使用import引入其他組件。新範例中定義了兩個函數:一個用於反轉字串,另一個用於彈出警告框。透過按鈕點擊可觸發這些功能。這些範例簡單易懂,實作會比閱讀文件更有效率!
Thumbnail
這次可以將範例內容轉移到components資料夾中,並在App.vue中引用它們。在App.vue中使用import引入其他組件。新範例中定義了兩個函數:一個用於反轉字串,另一個用於彈出警告框。透過按鈕點擊可觸發這些功能。這些範例簡單易懂,實作會比閱讀文件更有效率!
Thumbnail
<Suspense> 是 Vue 3 的一個實驗性組件,用於協調異步組件的加載狀態,簡化異步處理。它能在等待多個嵌套組件的異步依賴解決時顯示加載指示器,避免每個組件獨立處理加載和錯誤狀態,從而提高用戶體驗。
Thumbnail
<Suspense> 是 Vue 3 的一個實驗性組件,用於協調異步組件的加載狀態,簡化異步處理。它能在等待多個嵌套組件的異步依賴解決時顯示加載指示器,避免每個組件獨立處理加載和錯誤狀態,從而提高用戶體驗。
Thumbnail
使用 defineAsyncComponent 函數可實現此功能,它接受一個返回 Promise 的加載函數。在大型應用中,組件可以按需加載,並且可與 ES 模塊的動態導入結合使用。還可以使用高級選項處理加載和錯誤狀態,例如設置加載組件和超時設定。
Thumbnail
使用 defineAsyncComponent 函數可實現此功能,它接受一個返回 Promise 的加載函數。在大型應用中,組件可以按需加載,並且可與 ES 模塊的動態導入結合使用。還可以使用高級選項處理加載和錯誤狀態,例如設置加載組件和超時設定。
Thumbnail
通過使用插槽,組件可以變得更加靈活和可重用,例如 <FancyButton> 可以讓父組件提供按鈕的內部內容,而 <BaseLayout> 則可以使用命名插槽來指定不同區域的內容。插槽還可以設置預設內容,當父組件未提供插槽內容時,會渲染預設內容。
Thumbnail
通過使用插槽,組件可以變得更加靈活和可重用,例如 <FancyButton> 可以讓父組件提供按鈕的內部內容,而 <BaseLayout> 則可以使用命名插槽來指定不同區域的內容。插槽還可以設置預設內容,當父組件未提供插槽內容時,會渲染預設內容。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News