astatus
异步状态信号。没有数据,没有获取——只有舞台。
import astatus from "astatus";
const AS = astatus();
AS.pending();
await fetchUser();
await processData(); // however many steps
AS.success(); // you decide when
大多数异步状态库将状态绑定到数据或获取逻辑。 astatus 不喜欢。
这是一个独立的信号,你可以把它注入任何流中,在你选择的任何点。
安装
npm install astatus
使用
import astatus, { STATUS } from "astatus";
const loginAS = astatus({ name: "login" });
// Inject status at the right moment
loginAS.pending();
const data = await fetchUser();
await syncStore(data); // sync or async, as many steps as needed
loginAS.success();
// Read
console.log(loginAS.status); // 'success'
console.log(loginAS.isSuccess); // true
API
所有的例子都使用
const AS = astatus()除非另有说明。
创建
astatus({ name?, status? })
| 选项 | 类型 | 默认的 | 描述 |
|---|---|---|---|
name | string | null | 调试日志名称 |
status | string | 'initial' | 初始状态 |
状态阶段
astatus 管理四个内置阶段。这些是库的核心——其他一切都建立在它们之上。
| 阶段 | 描述 |
|---|---|
initial | 尚未启动-默认值 |
pending | 在进步 |
success | 成功完成 |
failure | 失败,带有可选的错误值 |
您可以通过调用相应的方法在这四个阶段之间移动。这就是整个想法。
AS.pending();
await doSomething();
AS.success();
对于生命周期之外的任何东西, AS.custom('uploading') 接受任何字符串。
注入
AS.initial()
AS.pending()
AS.success()
AS.failure(error?) // optional error value
AS.custom('uploading') // any string outside built-in stages
读
AS.status; // 'initial' | 'pending' | 'success' | 'failure' | custom
AS.error; // value passed to failure(), otherwise null
AS.isInitial;
AS.isPending;
AS.isSuccess;
AS.isFailure;
AS.isCustom; // true if current status is not a built-in stage
AS.isLocked;
观察
// All changes
const unsub = AS.subscribe((curr, prev) => {
console.log(curr.status, prev.status)
})
// Specific status — triggers on both entry and exit
const unwatch = AS.watch('success', (curr, prev) => { ... })
AS.watch(['success', 'failure'], (curr, prev) => { ... })
// Entry only — triggers once on transition into the status
const unwatch = AS.when('success', (curr, prev) => { ... })
// Cleanup
unsub()
unwatch()
等待
// As a timing gate — wait for the right moment, then continue
await AS.wait();
await AS.wait("success");
// As a result — inspect what happened
const { status, error, timeout, immediate } = await AS.wait();
const result = await AS.wait(["success", "failure"], 15); // timeout in seconds
| 场 | 描述 |
|---|---|
status | 解析时的状态(快照) |
error | 解析时错误 |
timeout | true 如果超时 |
immediate | true 如果已经处于目标状态 |
destroyed | true 如果实例在解析之前被销毁 |
如果 destroy() 被称为while a wait() 是悬而未决的,它立即解决 destroyed: true.
锁
AS.lock(); // block all status changes
AS.unlock(); // unblock
重置/销毁
AS.reset(); // back to initial, clears error and lock
AS.destroy(); // resolves all pending wait()s, clears all listeners, blocks all further changes
状态不变
import { STATUS } from "astatus";
STATUS.INITIAL; // 'initial'
STATUS.PENDING; // 'pending'
STATUS.SUCCESS; // 'success'
STATUS.FAILURE; // 'failure'
Vue / next
astatus 包括一个Vue可组合的开箱即用。不需要额外的安装。
import { useAstatus } from "astatus/vue";
基本用法
<script setup>
import { useAstatus } from "astatus/vue";
const loginAS = useAstatus({ name: "login" });
const handleLogin = async () => {
loginAS.pending();
try {
await fetchUser();
loginAS.success();
} catch (e) {
loginAS.failure(e);
}
};
</script>
<template>
<button :disabled="loginAS.isPending" @click="handleLogin">
{{ loginAS.isPending ? "Loading..." : "Login" }}
</button>
<p v-if="loginAS.isFailure">{{ loginAS.error }}</p>
</template>
反应性
status 和 error 是只读引用。 isInitial, isPending, isSuccess, isFailure, isCustom 都是计算值——都是响应式的,可以安全地在模板中使用。
ref在模板中会自动展开,所以 .value 这里不需要。
const AS = useAstatus();
// script: use .value
watch(AS.isPending, (val) => {
console.log("pending:", val);
});
// template: no .value needed
// <p v-if="AS.isPending">...</p>
注意: 破坏破坏了反应性。总是直接使用返回的对象。
// ✅ const loginAS = useAstatus(); // loginAS.isPending in template // ❌ reactivity lost const { isPending } = useAstatus();
自动清理
可组合的自动调用 destroy() 通过卸载组件 onUnmounted. 在大多数情况下不需要手动清理。
如果你使用 useAstatus 在组件外部(例如在一个Pinia store中),自动清理不适用- call destroy() 手动完成时。
// Pinia store
const AS = useAstatus();
// when no longer needed
AS.destroy();
要使实例在其组件之后保持存活(例如,在路由更改时缓存),pass autoDestroy: false. 你拥有它的生命周期-呼叫 destroy() 如果它应该结束的话,你自己。在组件内部创建时需要Vue 3.5+,因为早期版本在卸载时停止组件的计算。
const cache = {};
const boardAS = (cache.board ??= useAstatus({ name: "board", autoDestroy: false }));
next中的wait()
wait() 使用 setTimeout 在内部。在next中,避免在SSR期间调用它-在内部使用它 onMounted 或者用 import.meta.client.
// ✅ safe
onMounted(async () => {
await AS.wait();
});
// ✅ safe
if (import.meta.client) {
await AS.wait();
}
要求
- Vue >= 3.3.0
笔记
subscribe/watch/when返回一个退订函数——调用它来清理。destroy()解决所有悬而未决的问题wait()立即调用,然后清除所有侦听器。- 侦听器错误被捕获并单独记录,而不会破坏其他侦听器。
许可证
麻省理工学院
自述部分编辑与人工智能的帮助。