svas
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesesvas — Svelte Async Stores
svas — Svelte 异步存储
Stores that fetch lazily, cache, revalidate, and persist. Every store emits one of three types:
ts
type Maybe<T, E extends Error = Error> = null | T | E
// null → no data yet (loading / cleared / not fetched)
// T → resolved value
// E → fetch error (errors are values, never thrown)ts
import {
value, values, collection, // stores
ok, ensure, having, awaited, once, // guards & awaiting
combined, sync, Async, // compose & render
type Maybe
} from 'svas'这类存储支持延迟获取、缓存、重新验证与持久化功能。每个存储会输出以下三种类型之一:
ts
type Maybe<T, E extends Error = Error> = null | T | E
// null → 尚无数据(加载中 / 已清空 / 未获取)
// T → 已解析的值
// E → 获取错误(错误作为值返回,不会抛出)ts
import {
value, values, collection, // stores
ok, ensure, having, awaited, once, // guards & awaiting
combined, sync, Async, // compose & render
type Maybe
} from 'svas'Shared lifecycle
通用生命周期
Every store fetches on first subscribe, then auto-revalidates. Common options:
| Option | Meaning |
|---|---|
| fetcher returning |
| ms before re-fetch (default |
| mirror into local storage under this key |
| use |
| keep previous value visible while revalidating (default |
| |
| initial value when nothing is persisted |
每个存储会在首次订阅时获取数据,之后自动重新验证。通用配置项如下:
| 配置项 | 说明 |
|---|---|
| 返回 |
| 重新获取数据的间隔毫秒数(默认 |
| 将数据镜像存储到localStorage中,使用该配置项作为键名 |
| 使用 |
| 重新验证时保留之前的值可见(默认 |
| |
| 无持久化数据时的初始值 |
Stores
存储类型
All stores implements Readable interface from svelte/store.
Use whenever it makes sense to persist the data, it will vastly speed up the initial load.
If store contains user-bound data, use to reset the store when the user is logged out.
persistbind所有存储都实现了svelte/store中的Readable接口。
只要适合持久化数据,就使用配置项,它能大幅提升初始加载速度。如果存储包含与用户绑定的数据,使用配置项在用户登出时重置存储。
persistbindvalue<T>
— one async value
value<T>value<T>
— 单个异步值
value<T>Writable<T | null>ts
const me = value<User>({ get: () => api.me(), persist: 'user' })
const seen = value<number>({ persist: 'seen', default: 0 }) // transient/local-onlyMethods: , , (sync read), (revalidate if stale).
set(v)update(fn)extract(): T | nullsync()Writable<T | null>ts
const me = value<User>({ get: () => api.me(), persist: 'user' })
const seen = value<number>({ persist: 'seen', default: 0 }) // 临时/仅本地存储方法:、、(同步读取)、(若数据过期则重新验证)。
set(v)update(fn)extract(): T | nullsync()values<T>
— keyed cache
values<T>values<T>
— 键值缓存
values<T>A map of independent lifecycles, one per key.
Readable<Maybe<T>>ts
const products = values<Product>({ get: (id) => api.product(id), stale: true, persist: 'products' })
const one = products.get('42') // Readable<Maybe<Product>>, fetches if missing
products.set('42', next) // write by key
products.extract('42') // Product | null, syncMethods: · · (restore stashed value) · · · .
get(key, { fetch? })set(key, v, { stash? })reset(key)extract(key)delete(key)clear()Extra options: (don't revalidate persisted entries on startup). on remembers the prior persisted value so can roll back — use for optimistic updates.
permanentstash: truesetreset(key)一个由独立生命周期组成的映射,每个键对应一个生命周期。
Readable<Maybe<T>>ts
const products = values<Product>({ get: (id) => api.product(id), stale: true, persist: 'products' })
const one = products.get('42') // Readable<Maybe<Product>>,不存在时会获取数据
products.set('42', next) // 按键写入数据
products.extract('42') // Product | null,同步读取方法: · · (恢复暂存的值)· · · 。
get(key, { fetch? })set(key, v, { stash? })reset(key)extract(key)delete(key)clear()额外配置项:(启动时不对持久化条目进行重新验证)。调用时设置会记住之前的持久化值,以便可以回滚——适用于乐观更新场景。
permanentsetstash: truereset(key)collection<T>
— list of Identifiable
items
collection<T>Identifiablecollection<T>
— 可识别项列表
collection<T>Readable<Maybe<T[]>>{ id: string }valuesget(id)ts
const todos = collection<Todo>({
get: () => api.todos(),
values: values<Todo>(), // enables todos.get(id) / extract(id)
stale: true,
persist: 'todos',
bind: session
})Methods: · · (replace by id; inserts if absent) · · · · / (require ) · · .
subscribeadd(item)set(item, { add? })addupdate(id, fn, opts?)delete(id)replace(items)get(id)extract(id)valuessync(): thisfetch(): Promise<this>Mutations mirror into the store, so components subscribed via update without re-fetching.
valuesget(id)Readable<Maybe<T[]>>{ id: string }valuesget(id)ts
const todos = collection<Todo>({
get: () => api.todos(),
values: values<Todo>(), // 启用 todos.get(id) / extract(id)
stale: true,
persist: 'todos',
bind: session
})方法: · · (按id替换;若不存在则会插入)· · · · /(需要传入存储)· · 。
subscribeadd(item)set(item, { add? })addupdate(id, fn, opts?)delete(id)replace(items)get(id)extract(id)valuessync(): thisfetch(): Promise<this>变更会同步到存储中,因此通过订阅的组件无需重新获取数据即可更新。
valuesget(id)Guards & extraction
守卫与提取
Never use on a — an has no domain properties. Narrow first.
?.Maybe<T>Errorts
ok($store) // boolean type guard: narrows Maybe<T> → T (excludes null | Error)
ensure(store) // sync read, THROWS if null/Error — use when value must exist now (e.g. unsafe net requests in response to user action)
store.extract(key?) // sync read, T | null (ignores errors) — never throwsts
if (ok($todos)) $todos.length // typed as T
items.filter((i) => ok(i.account) && !i.account.deleted) // ✅ guard before access切勿在类型上使用操作符——Error对象没有领域属性。请先进行类型收窄。
Maybe<T>?.ts
ok($store) // boolean类型守卫:将Maybe<T>收窄为T(排除null | Error)
ensure(store) // 同步读取,若为null/Error则抛出错误——适用于当前必须存在值的场景(例如响应用户操作的非安全网络请求)
store.extract(key?) // 同步读取,返回T | null(忽略错误)——永远不会抛出错误ts
if (ok($todos)) $todos.length // 类型为T
items.filter((i) => ok(i.account) && !i.account.deleted) // ✅ 访问前先进行守卫检查Awaiting
等待处理
ts
await having(store) // first non-null value; REJECTS on Error — services needing auth
await awaited(store) // first non-null value; returns Error as a value (never rejects)
await once(store, (v) => v === 'ready') // first value satisfying a conditionts
await having(store) // 获取第一个非null值;若遇到Error则拒绝——适用于需要认证的服务
await awaited(store) // 获取第一个非null值;将Error作为值返回(永远不会拒绝)
await once(store, (v) => v === 'ready') // 获取第一个满足条件的值Compose & render
组合与渲染
<Async>
— render a Maybe
<Async>Maybe<Async>
— 渲染Maybe类型
<Async>svelte
<Async store={todos}>
{#snippet awaited(todos)}
<!-- here todos are T[] -->
{#each todos as t}<Row {t} />{/each}
{/snippet}
{#snippet waiting()}<Spinner />{/snippet} <!-- optional; default loader otherwise -->
{#snippet error(e)}<Err {e} />{/snippet} <!-- optional; default error UI otherwise -->
</Async>Props: (required), snippet (required), optional / snippets, (suppress default loader/error chrome). Combine with to await several at once.
storeawaitedwaitingerrorsilentcombinedsvelte
<Async store={todos}>
{#snippet awaited(todos)}
<!-- 此处todos为T[]类型 -->
{#each todos as t}<Row {t} />{/each}
{/snippet}
{#snippet waiting()}<Spinner />{/snippet} <!-- 可选;否则使用默认加载器 -->
{#snippet error(e)}<Err {e} />{/snippet} <!-- 可选;否则使用默认错误UI -->
</Async>属性:(必填)、代码片段(必填),可选的/代码片段,(禁用默认加载器/错误界面)。可与结合使用以同时等待多个存储。
storeawaitedwaitingerrorsilentcombinedcombined(...stores)
combined(...stores)combined(...stores)
combined(...stores)One from many: tuple when all resolve, first , else . Spreadable.
MaybeErrornullsvelte
<Async store={combined(account, todos)}>
{#snippet awaited([account, todos])}
<!-- here account is U and todos is T[] -->
<Profile {account} />
{#each todos as t}<Row {t} />{/each}
{/snippet}
</Async>将多个存储合并为一个:当所有存储都解析完成时返回元组,若遇到第一个Error则返回该Error,否则返回null。支持展开操作。
Maybesvelte
<Async store={combined(account, todos)}>
{#snippet awaited([account, todos])}
<!-- 此处account为U类型,todos为T[]类型 -->
<Profile {account} />
{#each todos as t}<Row {t} />{/each}
{/snippet}
</Async>sync(store, item, { delete? })
sync(store, item, { delete? })sync(store, item, { delete? })
sync(store, item, { delete? })Conflict-free update.
T must implement interface Comparable { id: string; _version: number;_deleted?: number | null }
Merge a versioned item into a or , respecting ; removes on (unless ). For applying server/realtime events.
collectionvalue_version_deleteddelete: falsets
events.on('todos.sync', (todo) => sync(todos, todo))无冲突更新。
T必须实现Comparable接口:{ id: string; _version: number;_deleted?: number | null }
将带版本号的项合并到或存储中,遵循规则;当存在时移除该项(除非)。适用于应用服务器/实时事件场景。
collectionvalue_version_deleteddelete: falsets
events.on('todos.sync', (todo) => sync(todos, todo))Rules
规则
- Errors are values — fetchers and services return ; check
T | Error, neverinstanceof Errorfor expected failures.try/catch - Guard before access — /
ok()/ensure(), neverextract()on?..Maybe<T> - One store per source — derive everything else; don't duplicate fetched data into local state.
- Lazy by design — a store does nothing until subscribed; ,
$store,<Async>,get, orhavingtriggers it..subscribe
- 错误是值 — 获取函数和服务返回;通过
T | Error进行检查,切勿对预期的失败使用instanceof Error。try/catch - 访问前先守卫 — 使用/
ok()/ensure(),切勿在extract()上使用Maybe<T>。?. - 每个数据源对应一个存储 — 其他所有数据都从该存储派生;不要将获取到的数据复制到本地状态中。
- 设计为延迟加载 — 存储在被订阅前不会执行任何操作;、
$store、<Async>、get或having会触发它。.subscribe
Advanced
进阶内容
For derived stores with live subscriptions/cleanup, realtime event wiring, linked/enriched entities, and optimistic update patterns, see references/patterns.md.
Maybe如需了解带有实时订阅/清理、实时事件连接、关联/增强实体以及乐观更新模式的派生存储,请查看references/patterns.md。
Maybe