
TanStack Query AngularinjectIsRestoring 持久化恢复状态信号详解与竞态规避原理【免费下载链接】query Powerful asynchronous state management, server-state utilities and data fetching for the web. TS/JS, React Query, Solid Query, Svelte Query and Vue Query.项目地址: https://gitcode.com/GitHub_Trending/qu/queryinjectIsRestoring是tanstack/angular-query-experimental包提供的注入式 API返回一个只读Signalboolean用于追踪 Query 数据恢复restore过程是否正在进行。本篇基于仓库中的官方 API 文档与源码实现系统讲解该函数的签名、参数、返回值以及它如何被injectQuery、injectInfiniteQuery内部消费来消除恢复期发起多余请求的竞态条件并展示它与持久化客户端persist client的完整协作链路。读完本文你将能够在 Angular 应用中正确使用该信号控制恢复期 UI 行为并理解 TanStack Query Angular 版避免恢复期请求风暴的底层机制。API 签名与官方定义官方参考文档docs/framework/angular/reference/functions/injectIsRestoring.md 对应仓库路径为 docs/framework/angular/reference/functions/injectIsRestoring.md给出的函数签名为function injectIsRestoring(options?: InjectIsRestoringOptions): Signalboolean;其定义位于 packages/angular-query-experimental/src/inject-is-restoring.ts#L32文档对其职责的描述为Injects a signal that tracks whether a restore is currently in progress.injectQueryand friends also check this internally to avoid race conditions between the restore and initializing queries.注入一个追踪当前是否正在进行恢复过程的信号injectQuery等函数也会在内部检查它以避免恢复过程与查询初始化之间的竞态条件。参数optionsoptions为可选参数类型为InjectIsRestoringOptions即injectIsRestoring 的选项。从源码结构看该接口见 inject-is-restoring.ts#L18-L25只包含一个字段字段类型说明injectorInjector可选用于获取 isRestoring 信号的Injector。不提供时使用当前注入上下文通过 Angular 的inject这一点在实际调用上意味着两种合法用法注入上下文中无参调用在组件构造函数、字段初始化、provide回调等注入上下文中直接injectIsRestoring()任意位置传入 Injector在普通函数、工具类等非注入上下文中通过injectIsRestoring({ injector: myInjector })显式指定注入器。返回值返回一个只读Signalboolean其值指示当前是否正在进行数据恢复。只读体现在当应用没有显式提供恢复信号时底层默认工厂返回的就是signal(false).asReadonly()见 inject-is-restoring.ts#L13-L16业务侧无法也不应写这个信号。内部实现IS_RESTORING 令牌与默认值机制理解injectIsRestoring行为的关键在于它背后的内部注入令牌。在 packages/angular-query-experimental/src/inject-is-restoring.ts#L10-L16 中/** * Internal token used to track isRestoring state, accessible in public API * through injectIsRestoring and set via provideIsRestoring */ const IS_RESTORING new InjectionToken(, { // Default value when not provided factory: () signal(false).asReadonly(), })从源码结构看整个机制由三部分构成IS_RESTORING令牌私有令牌带默认工厂。当应用未提供恢复信号时Injector.get(IS_RESTORING)会走工厂得到一个恒为false的只读信号——即未启用持久化恢复时永远不处于恢复状态injectIsRestoring消费端见 inject-is-restoring.ts#L32-L36export function injectIsRestoring(options?: InjectIsRestoringOptions) { !options?.injector assertInInjectionContext(injectIsRestoring) const injector options?.injector ?? inject(Injector) return injector.get(IS_RESTORING) }注意第 33 行的上下文断言只有当传入options.injector时才会跳过assertInInjectionContext检查。若在组件/服务注入上下文之外、又未传injector就调用它Angular 会抛出NG0203错误。测试tests/inject-is-restoring.test.ts#L88-L92 明确验证了这一行为断言错误信息包含NG0203及injectIsRestoring。provideIsRestoring提供端见 inject-is-restoring.ts#L38-L48接收一个Signalboolean并返回覆盖IS_RESTORING令牌的Provider。它的 API 文档见 docs/framework/angular/reference/functions/provideIsRestoring.md其定位是供 TanStack Query Angular 持久化客户端插件提供追踪恢复状态的信号。injectIsRestoring与provideIsRestoring均从包入口公开导出index.ts#L34。核心用途一injectQuery / injectInfiniteQuery 内部规避恢复期竞态官方文档点明injectQuery和它的兄弟们会在内部检查该信号。这一说法在源码中有直接对应。injectQuery与injectInfiniteQuery共享同一基础实现createBaseQuerypackages/angular-query-experimental/src/create-base-query.ts其中有两处消费injectIsRestoring()1. 恢复期将乐观结果标记为isRestoringcreate-base-query.ts#L50-L64const isRestoring injectIsRestoring() // ... const defaultedOptionsSignal computed(() { const defaultedOptions queryClient.defaultQueryOptions(optionsFn()) defaultedOptions._optimisticResults isRestoring() ? isRestoring : optimistic return defaultedOptions })_optimisticResults是 query-core 层的选项取值isRestoring时观察者observer会跳过对缓存数据的乐观计算从而保证恢复完成前 UI 读到的是恢复中语义而非未就绪的中间态。2. 恢复期完全不订阅观察者、不触发请求create-base-query.ts#L108-L115effect((onCleanup) { const observer observerSignal() // ... const unsubscribe isRestoring() ? () undefined : untracked(() ngZone.runOutsideAngular(() { return observer.subscribe(/* 结果写回 resultFromSubscriberSignal */) })) // ... })当isRestoring()为true时unsubscribe是一个空函数即 effect 不建立对QueryObserver的订阅queryFn不会被调度执行信号翻转为false后 effect 重跑才开始正常订阅与请求。这正是避免恢复过程与初始化查询之间的竞态的具体实现。测试用例对此有直接验证tests/inject-query.test.ts#L636-L666 在提供provideIsRestoring(signal(true).asReadonly())后注册injectQuery推进虚拟时钟 11ms超过queryFn的 10ms 延迟后断言query.status()仍为pending、fetchStatus()为idle且queryFn调用次数为 0。injectInfiniteQuery的等价测试位于tests/inject-queries.test.ts#L183-L184。核心用途二配合持久化客户端persist clientinjectIsRestoring的典型生产场景是与tanstack/angular-query-persist-client包配合。该包的 with-persist-query-client.ts#L55-L88 展示了完整的状态机export function withPersistQueryClient( persistQueryClientOptions: PersistQueryClientOptions, ): PersistQueryClientFeature { const isRestoring signal(true) // 恢复期起点true const providers [ provideIsRestoring(isRestoring.asReadonly()), // 对外暴露只读信号 { provide: ENVIRONMENT_INITIALIZER, multi: true, useValue: () { if (!isPlatformBrowser(inject(PLATFORM_ID))) return const destroyRef inject(DestroyRef) const queryClient inject(QueryClient) // ... persistQueryClientRestore(options) .then(() { onSuccess?.() }) .catch(() { onError?.() }) .finally(() { isRestoring.set(false) // 恢复结束成功/失败翻转为 false const cleanup persistQueryClientSubscribe(options) destroyRef.onDestroy(cleanup) }) }, }, ] return queryFeature(PersistQueryClient, providers) }从源码结构看其生命周期为环境初始化时创建signal(true)并立即通过provideIsRestoring暴露只读视图 → 浏览器平台下执行persistQueryClientRestore从 storage 恢复 Query 缓存 → 恢复流程在finally中无论成功或失败将信号置为false同时注册persistQueryClientSubscribe监听后续变更并写入存储。由此形成闭环恢复期所有injectQuery/injectInfiniteQuery挂起不请求恢复完成信号翻转后才开始正常初始化避免恢复期发出 N 个与缓存重复的请求。该包 JSDoc 中给出的应用级配置示例同样见 with-persist-query-client.ts#L30-L50const localStoragePersister createAsyncStoragePersister({ storage: window.localStorage, }) export const appConfig: ApplicationConfig { providers: [ provideTanStackQuery( new QueryClient(), withPersistQueryClient({ persistOptions: { persister: localStoragePersister, }, onSuccess: () console.log(Restoration completed successfully.), }) ), ], };在此配置下业务组件无需做任何额外接线即可享受恢复期请求抑制而当你需要在组件层面感知是否仍在恢复以渲染骨架屏或禁用按钮时就调用injectIsRestoring()Component({ selector: app-profile, template: if (isRestoring()) { p正在恢复本地数据…/p } else { {{ query.data() ?? 加载中… }} } , }) export class ProfileComponent { // 必须在注入上下文中调用构造函数/字段初始化 readonly isRestoring injectIsRestoring() readonly query injectQuery(() ({ queryKey: [profile], queryFn: fetchProfile, })) }行为语义与测试验证汇总官方测试文件tests/inject-is-restoring.test.ts 覆盖了该 API 的全部语义边界可作为行为契约参考场景断言结果未使用provideIsRestoring默认工厂isRestoring()返回false通过provideIsRestoring(signal(true).asReadonly())提供返回true提供者信号由true→false→true变化注入的信号反应式跟随变化非注入上下文 injector选项可正常调用并返回正确值非注入上下文且未传injector抛出NG0203错误信息含injectIsRestoring使用注意与适用前提调用位置约束默认走inject注入上下文务必在组件构造函数、字段初始化器等注入上下文中调用普通函数中请显式传入{ injector }否则触发NG0203。只读语义返回的是只读信号且默认值恒为false。不要自行provideIsRestoring一个手写信号来模拟恢复状态——提供端是持久化插件的契约见 provideIsRestoring.md 的定位说明误用会干扰injectQuery内部的恢复期抑制逻辑。适用前提injectIsRestoring属于实验性包tanstack/angular-query-experimental恢复信号只有在引入withPersistQueryClienttanstack/angular-query-persist-client见 packages/angular-query-persist-client或自行provideIsRestoring后才会从false变为true。未启用持久化的应用中该信号永远为falseinjectQuery内部的两处消费_optimisticResults标记与订阅挂起也随之不产生实际影响。与相关 API 的关系provideIsRestoring是injectIsRestoring的配对提供端查询侧入口可参考 injectQuery.md 与 injectInfiniteQuery.md。【免费下载链接】query Powerful asynchronous state management, server-state utilities and data fetching for the web. TS/JS, React Query, Solid Query, Svelte Query and Vue Query.项目地址: https://gitcode.com/GitHub_Trending/qu/query创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考