Vue Academy · บทเรียน

คอมโพเนนต์ Vue Suspense

พร้อมสล็อต default และ #fallback การโหลดคอมโพเนนต์แบบอะซิงโครนัส และ Suspense ซ้อนกัน

บทเรียน 1 จาก 413 ขั้นตอน

คอมโพเนนต์ Vue Suspense เป็นบทเรียน Vue Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Vue Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Vue Academy มีบทเรียนทั้งหมด 4 บทเรียน

ปัญหาที่ Suspense แก้ได้

Suspense คือคอมโพเนนต์ Vue ในตัวที่ประสานสถานะการโหลดสำหรับคอมโพเนนต์ที่มีการพึ่งพาแบบอะซิงโครนัส

หากไม่มีสิ่งนี้ คอมโพเนนต์แบบอะซิงโครนัสแต่ละรายการจะต้องจัดการตัวหมุนแสดงการโหลดของตนเอง แต่เมื่อใช้ Suspense คุณจะประกาศขอบเขตเดียวที่รอการทำงานแบบอะซิงโครนัสที่ซ้อนกันทั้งหมด และแสดงเนื้อหาสำรองเดียวจนกว่าทุกอย่างจะพร้อม

สองช่อง: เนื้อหาหลักและเนื้อหาสำรอง

Suspense เปิดเผยช่องที่มีชื่อไว้สองช่อง:

  • default — เนื้อหาจริง ซึ่งอาจมีคอมโพเนนต์แบบอะซิงโครนัสหรือ setup() แบบอะซิงโครนัส
  • fallback — สิ่งที่จะแสดงขณะที่ช่อง default กำลังแก้ไขการพึ่งพา

เมื่อการพึ่งพาแบบอะซิงโครนัสทั้งหมดเสร็จสิ้น Vue จะแทนที่เนื้อหาสำรองด้วยเนื้อหาหลัก

<template>
  <Suspense>
    <template #default>
      <UserDashboard />
    </template>
    <template #fallback>
      <div class="spinner">Loading dashboard...</div>
    </template>
  </Suspense>
</template>

setup() แบบอะซิงโครนัสในฐานะการพึ่งพา

คอมโพเนนต์จะกลายเป็นการพึ่งพาแบบอะซิงโครนัสเมื่อฟังก์ชัน setup() ของคอมโพเนนต์ประกาศเป็น async และรอการทำงานบางอย่าง Vue จะติดตามพรอมิสที่ส่งคืนมา

รูปแบบที่เทียบเท่ากันของ <script setup> คือการใช้ await ระดับบนสุดโดยตรงภายในบล็อก

<script setup>
import { ref } from 'vue'

// Top-level await makes this an async dependency of Suspense
const res = await fetch('/api/profile')
const profile = ref(await res.json())
</script>

<template>
  <h1>Welcome, {{ profile.name }}</h1>
</template>

คอมโพเนนต์แบบอะซิงโครนัสก็นับรวมด้วย

คอมโพเนนต์ที่สร้างด้วย defineAsyncComponent จะถูกติดตามโดย Suspense เช่นกัน เนื้อหาสำรองจะยังคงแสดงจนกว่า import() แบบไดนามิกจะแก้ไขเสร็จ

วิธีนี้ช่วยให้คุณแบ่งโค้ดของคอมโพเนนต์ขนาดใหญ่โดยไม่ต้องเขียนส่วนติดต่อผู้ใช้สำหรับการโหลดแยกในแต่ละคอมโพเนนต์

<script setup>
import { defineAsyncComponent } from 'vue'

const Chart = defineAsyncComponent(() =>
  import('./HeavyChart.vue')
)
</script>

<template>
  <Suspense>
    <Chart />
    <template #fallback>Preparing chart...</template>
  </Suspense>
</template>

การรอคอมโพเนนต์ลูกแบบอะซิงโครนัสหลายรายการร่วมกัน

หากช่องเริ่มต้นมีการพึ่งพาแบบอะซิงโครนัสหลายรายการ Suspense จะรอให้ทั้งหมดดำเนินการเสร็จสมบูรณ์ก่อนแสดงเนื้อหา

วิธีนี้ช่วยป้องกันการเลื่อนของเค้าโครงจากคอมโพเนนต์ที่ปรากฏทีละรายการ

<template>
  <Suspense>
    <div>
      <UserStats />   <!-- async setup -->
      <RecentOrders /> <!-- async setup -->
      <Recommendations /> <!-- async component -->
    </div>
    <template #fallback>
      <PageSkeleton />
    </template>
  </Suspense>
</template>

การดักจับการปฏิเสธด้วย onErrorCaptured

หาก setup() แบบอะซิงโครนัสไม่สำเร็จ (เช่น การดึงข้อมูลล้มเหลว) ข้อผิดพลาดจะส่งต่อขึ้นไปยังฮุก onErrorCaptured ที่อยู่ใกล้ที่สุดในคอมโพเนนต์แม่

Suspense เองไม่แสดงข้อผิดพลาด ดังนั้นจึงควรใช้ร่วมกับขอบเขตข้อผิดพลาด

<script setup>
import { ref, onErrorCaptured } from 'vue'

const error = ref(null)

onErrorCaptured((err) => {
  error.value = err
  return false // stop the error from propagating further
})
</script>

รูปแบบขอบเขตข้อผิดพลาดร่วมกับ Suspense

รูปแบบที่ใช้กันทั่วไปในระบบจริงคือการครอบ Suspense ไว้ภายในคอมโพเนนต์ขอบเขตข้อผิดพลาด โดย onErrorCaptured จะคืนค่า false เพื่อหยุดการส่งต่อและแสดงส่วนติดต่อผู้ใช้สำหรับข้อผิดพลาดแทน

<script setup>
import { ref, onErrorCaptured } from 'vue'
const err = ref(null)
onErrorCaptured((e) => { err.value = e; return false })
</script>

<template>
  <p v-if="err">Failed to load: {{ err.message }}</p>
  <Suspense v-else>
    <ProfilePanel />
    <template #fallback>Loading...</template>
  </Suspense>
</template>

เหตุการณ์ @pending และ @resolve

Suspense ส่งเหตุการณ์วงจรชีวิตที่คุณสามารถรับฟังได้ดังนี้:

  • @pending — ถูกเรียกเมื่อเข้าสู่สถานะรอดำเนินการ (กำลัง loading)
  • @resolve — ถูกเรียกเมื่อช่องเริ่มต้นดำเนินการเสร็จสมบูรณ์
  • @fallback — ถูกเรียกเมื่อแสดงเนื้อหา fallback

มีประโยชน์สำหรับการวิเคราะห์การใช้งานหรือแถบความคืบหน้า

<template>
  <Suspense @pending="onPending" @resolve="onResolve">
    <RouteView />
    <template #fallback>Loading route...</template>
  </Suspense>
</template>

พร็อพ timeout สำหรับ fallback ที่ล่าช้า

พร็อพ timeout (หน่วยเป็นมิลลิวินาที) จะหน่วงการแสดง fallback หากงานแบบอะซิงโครนัสเสร็จเร็วกว่าค่า timeout ก็จะไม่แสดง fallback

วิธีนี้ช่วยป้องกันไม่ให้ตัวหมุนโหลดปรากฏขึ้นชั่วขณะสำหรับการตอบกลับที่รวดเร็ว

<template>
  <!-- Only show fallback if loading exceeds 200ms -->
  <Suspense :timeout="200">
    <FastPanel />
    <template #fallback>Loading...</template>
  </Suspense>
</template>

Suspense กับเราเตอร์และการเปลี่ยนผ่าน

Suspense สามารถใช้ร่วมกับ RouterView และ Transition เพื่อทำให้การเปลี่ยนเส้นทางแบบอะซิงโครนัสมีภาพเคลื่อนไหว ลำดับมีความสำคัญดังนี้: Transition ครอบ Suspense ซึ่งครอบคอมโพเนนต์ของเส้นทางอีกชั้นหนึ่ง

<template>
  <RouterView v-slot="{ Component }">
    <Transition mode="out-in">
      <Suspense>
        <component :is="Component" />
        <template #fallback>Loading page...</template>
      </Suspense>
    </Transition>
  </RouterView>
</template>

เมื่อใด NOT ควรใช้ Suspense

หลีกเลี่ยงการใช้ Suspense กับข้อมูลที่ต้องดึงใหม่บ่อยครั้งขณะที่คอมโพเนนต์ยังติดตั้งอยู่ เพราะ Suspense จะจัดการเฉพาะการดำเนินการแบบอะซิงโครนัสครั้งแรกเท่านั้น สำหรับสถานะกำลังโหลดที่เกิดขึ้นต่อเนื่อง (เช่น การแบ่งหน้าหรือการดึงข้อมูลใหม่) ให้ใช้รีฟแบบรีแอกทีฟ loading ตามปกติแทน

<script setup>
import { ref } from 'vue'
const loading = ref(false)
async function loadMore() {
  loading.value = true
  await fetchNextPage()
  loading.value = false
}
</script>

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ทดสอบความเข้าใจของคุณเกี่ยวกับ Suspense

สรุปทบทวน

คุณได้เรียนรู้วิธีที่ Suspense จัดการการพึ่งพาแบบอะซิงโครนัส:

  • ช่อง ค่าเริ่มต้นเก็บเนื้อหาแบบอะซิงโครนัส (การตั้งค่าแบบอะซิงโครนัสหรือคอมโพเนนต์แบบอะซิงโครนัส)
  • ช่อง fallback จะแสดงระหว่างกำลัง loading
  • จะรอคอมโพเนนต์ลูกแบบอะซิงโครนัสทั้งหมดก่อนแสดงเนื้อหา
  • การปฏิเสธจะส่งต่อไปยัง onErrorCaptured ในขอบเขตของคอมโพเนนต์แม่
  • timeout ช่วยป้องกันตัวหมุนโหลดปรากฏขึ้นชั่วขณะ ส่วนเหตุการณ์อย่าง @resolve ช่วยในการวิเคราะห์การใช้งาน
เริ่มต้นได้ฟรี

เรียนรู้ HTML ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
42
บทเรียน
156

คำถามที่พบบ่อย

บทเรียน “คอมโพเนนต์ Vue Suspense” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “คอมโพเนนต์ Vue Suspense” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Vue Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Vue Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “คอมโพเนนต์ Vue Suspense”

พร้อมสล็อต default และ #fallback การโหลดคอมโพเนนต์แบบอะซิงโครนัส และ Suspense ซ้อนกัน คุณปฏิบัติ Vue Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Vue Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Vue Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน

บทเรียน “คอมโพเนนต์ Vue Suspense” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Vue Academy นี้ได้ไหม

ได้ บทเรียน Vue Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. คอมโพเนนต์ Vue Suspense
  2. คอมโพเนนต์แบบอะซิงโครนัสด้วย defineAsyncComponent
  3. SSR แบบสตรีมด้วย renderToWebStream
  4. กลยุทธ์การไฮเดรตแบบเลื่อนเวลา
← กลับไปที่ Vue Academy