Async Patterns
นักพัฒนา React track async state ด้วยมือ: useState สามตัวสำหรับ loading, data, และ error แล้วต่อด้วย if/else chain ใน JSX React 18 เพิ่ม <Suspense> และ error boundary เพื่อทำให้ declarative ขึ้น แต่ต้อง setup เพิ่มและต้องใช้ data library ที่ throw Promise ได้
Svelte มีคำตอบเดียวที่หรูหรา ฝังอยู่ใน template syntax:
{#await promise} <!-- loading -->{:then value} <!-- resolved -->{:catch err} <!-- rejected -->{/await}บล็อกเดียว สามสถานะ ไม่มี hook ไม่มี error boundary component ไม่มีการ throw Promise ถ้าตัวแปร promise ถูกแทนที่ด้วย Promise ใหม่ (เช่น เมื่อผู้ใช้กด “Reload”) Svelte จะกลับเข้าสถานะ loading ให้อัตโนมัติ
Manual useState เทียบกับ {#await}
หัวข้อที่มีชื่อว่า “Manual useState เทียบกับ {#await}”function UserCard({ userId }) { const [user, setUser] = React.useState(null); const [loading, setLoading] = React.useState(true); const [error, setError] = React.useState(null);
React.useEffect(() => { setLoading(true); fetch(`/api/users/${userId}`) .then(r => r.json()) .then(data => { setUser(data); setLoading(false); }) .catch(err => { setError(err.message); setLoading(false); }); }, [userId]);
if (loading) return <p>Loading...</p>; if (error) return <p style={{ color: 'red' }}>Error: {error}</p>; return <div><h2>{user.name}</h2><p>{user.email}</p></div>;}<script> let { userId } = $props();
async function loadUser(id) { const res = await fetch(`/api/users/${id}`); if (!res.ok) throw new Error('Not found'); return res.json(); }
let userPromise = $derived(loadUser(userId));</script>
{#await userPromise} <p>Loading...</p>{:then user} <div> <h2>{user.name}</h2> <p>{user.email}</p> </div>{:catch err} <p style="color:red">Error: {err.message}</p>{/await}เมื่อ userId เปลี่ยน $derived จะสร้าง Promise ใหม่ และ {#await} จะกลับเข้าสถานะ pending ทันที ไม่ต้อง reset state ด้วยมือ
React Suspense เทียบกับ {#await}
หัวข้อที่มีชื่อว่า “React Suspense เทียบกับ {#await}”// React — requires library support (react-query, SWR, Relay)// The library must throw a Promise for Suspense to catch<Suspense fallback={<Spinner />}> <ErrorBoundary fallback={<ErrorUI />}> <UserCard userId={1} /> </ErrorBoundary></Suspense><!-- Svelte — no extra library, no boundary components -->{#await userPromise} <Spinner />{:then user} <UserCard {user} />{:catch err} <ErrorUI message={err.message} />{/await}ลองเล่น: simulated async พร้อม reload
หัวข้อที่มีชื่อว่า “ลองเล่น: simulated async พร้อม reload”Demo นี้ใช้ setTimeout จำลอง network call 500 ms ที่บางครั้ง reject กดปุ่ม “Load” เพื่อสร้าง Promise ใหม่ — {#await} จัดการทั้งสามสถานะให้อัตโนมัติ