网络模式(Network Mode)完整指南:online / always / offlineFirst 的机制与实战)
TanStack QueryVue Query网络模式Network Mode完整指南online / always / offlineFirst 的机制与实战【免费下载链接】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/queryTanStack Query在 Vue 生态中即tanstack/vue-query提供三种网络模式Network Mode用于控制查询Query与变更Mutation在没有网络连接时的行为。本文以 docs/framework/vue/guides/network-mode.md其权威内容对应 React 版 network-mode.md为骨架结合query-core的 retryer.ts、queryClient.ts 等源码深入讲解三种模式的取舍、paused状态的底层实现以及 Vue 组件中的实际用法。读完本文你将能根据离线优先 PWA、本地存储读取等不同场景精确选择并配置网络模式并理解重试暂停与恢复的完整链路。一、三种网络模式一览TanStack Query 提供了三种网络模式用于区分 Queries 与 Mutations 在无网络连接时应如何表现模式无网络时的行为典型场景online不发起请求进入paused状态重试也暂停纯网络数据获取默认模式always忽略网络状态照常请求失败即进入error读取AsyncStorage、内存缓存等不依赖网络的queryFnofflineFirst先执行一次queryFn失败后暂停重试有 serviceWorker 缓存或 HTTP 缓存的离线优先 PWA该模式可以针对单个 Query / Mutation 单独设置也可以通过 QueryClient 的全局默认配置统一设置。由于 TanStack Query 最常用于结合数据获取库进行数据抓取因此默认网络模式为online。对应的类型定义与签名位于 types.ts// packages/query-core/src/types.ts export type NetworkMode online | always | offlineFirstnetworkMode: online | always | offlineFirst可选默认值为online二、Network Mode: online默认模式在该模式下只要没有网络连接Queries 和 Mutations 就不会触发。如果某个查询因无网络而无法发起它会始终停留在其当前的statepending、error、success中。但与此同时会额外暴露一个 fetchStatus 字段取值有三种fetchingqueryFn真正在执行——请求正在进行中paused查询没有在执行——它被“暂停”了直到恢复网络连接才会继续idle查询既不在抓取也没有被暂停。isFetching与isPaused两个布尔标志由该状态派生并直接暴露方便在模板中直接使用。注意仅检查pending状态并不足以判断是否应显示加载动画。当组件首次挂载且恰好没有网络连接时查询可能处于state: pending但fetchStatus: paused。在 Vue 组件中两者可以这样区分使用script setup langts import { useQuery } from tanstack/vue-query const { isPending, isPaused, isFetching, data, error } useQuery({ queryKey: [todos], queryFn: fetchTodoList, }) /script template !-- 首次挂载且无网络时isPending 为 true 但 isPaused 也为 true -- span v-ifisPending !isPausedLoading.../span span v-else-ifisPending isPausedWaiting for network.../span span v-else-iferrorError: {{ error.message }}/span ul v-else-ifdata li v-fortodo in data :keytodo.id{{ todo.title }}/li /ul /templateuseQuery的响应式返回值来自对tanstack/query-core中QueryObserver的封装见 packages/vue-query/src/useQuery.ts因此isPending、isFetching、isPaused均为可被模板响应式追踪的状态。2.1 重试机制的暂停与恢复如果查询在联网状态下开始执行但请求进行中突然断网TanStack Query同样会暂停重试机制。暂停的查询会在重新联网后自动继续执行。这独立于refetchOnReconnect该选项在此模式下默认也是true因为这不是一次“重新抓取”refetch而是一次“继续”continue。如果在暂停期间查询被 取消则它不会再继续执行。三、Network Mode: always在该模式下TanStack Query始终发起请求完全忽略在线/离线状态。如果你的场景根本不需要真实网络连接——例如queryFn只是从AsyncStorage读取或者只是return Promise.resolve(5)——这就是最合适的选择查询永远不会因为无网络而进入paused状态重试也不会暂停——如果失败查询将直接进入error状态refetchOnReconnect在该模式下默认变为false因为“重新连接网络”不再是陈旧数据应被重新抓取的可靠信号当然你仍可以手动开启它。import { useQuery } from tanstack/vue-query const { data } useQuery({ queryKey: [settings], queryFn: async () { // 不依赖网络只读取本地缓存 return JSON.parse(localStorage.getItem(settings) ?? {}) }, networkMode: always, })这一默认值行为在源码中有明确实现queryClient.ts 中refetchOnReconnect仅在未显式指定时才根据networkMode ! always推导出默认值// packages/query-core/src/queryClient.ts (defaultQueryOptions 内部) if (defaultedOptions.refetchOnReconnect undefined) { defaultedOptions.refetchOnReconnect defaultedOptions.networkMode ! always }四、Network Mode: offlineFirst该模式是前两者的中间态先执行一次queryFn但之后暂停重试。它非常适合拥有拦截请求的 serviceWorker 并做缓存的 离线优先 PWA 场景或者通过 Cache-Control 响应头 使用 HTTP 缓存的场景。在这种情境下第一次抓取可能因为命中离线存储/缓存而成功而如果缓存未命中网络请求会发出并失败此时该模式表现得与online模式一致——暂停重试。import { useQuery } from tanstack/vue-query const { data } useQuery({ queryKey: [todos], queryFn: fetchTodoList, networkMode: offlineFirst, })值得注意的是当你在查询配置中使用了persister持久化器却没有显式指定networkMode时框架会自动为你补上offlineFirst因为“从持久化缓存恢复数据”本质上就是离线优先的读取场景// packages/query-core/src/queryClient.ts (defaultQueryOptions 内部) if (!defaultedOptions.networkMode defaultedOptions.persister) { defaultedOptions.networkMode offlineFirst }五、如何配置单查询级与全局级networkMode既可以写在单个useQuery/useMutation的配置里也可以放进QueryClient的全局默认配置或queryDefaults/mutationDefaults中统一生效// 全局默认配置所有查询默认使用 offlineFirst import { QueryClient } from tanstack/vue-query export const queryClient new QueryClient({ defaultOptions: { queries: { networkMode: offlineFirst, }, mutations: { networkMode: always, }, }, })配置解析的优先级为显式传入的 options 通过queryKey匹配的queryDefaultsdefaultOptions.queries全局默认见 queryClient.ts。因此单查询级配置始终拥有最高优先级。六、源码级原理paused 状态是如何产生的理解三种模式的本质关键在于query-core的两处核心实现网络状态的来源以及重试器的暂停/继续逻辑。6.1 网络状态来源OnlineManageronlineManager.ts 在浏览器环境监听window的online/offline事件并通过setOnline()通知所有订阅者isOnline()返回当前是否在线。离线状态完全由它驱动——这也是 Devtools 的 “Mock offline behavior” 按钮所操作的对象。6.2 能否开始抓取canFetchretryer.ts 中的canFetch是决定“现在能否发起请求”的核心函数// packages/query-core/src/retryer.ts export function canFetch(networkMode: NetworkMode | undefined): boolean { return (networkMode ?? online) online ? onlineManager.isOnline() : true }可以看到networkMode未指定时按online处理必须在线才能发起而always与offlineFirst则直接返回true先跑一次再说。6.3 暂停与继续pause / continue在createRetryer中start()会根据canStart()即canFetch(...) canRun()决定直接运行还是先pause()见 retryer.ts。暂停实现为一个挂起的 Promise通过闭包中的continueFn在条件满足时被唤醒// packages/query-core/src/retryer.ts const canContinue () focusManager.isFocused() (config.networkMode always || onlineManager.isOnline()) config.canRun() const pause () { return new Promise((continueResolve) { continueFn (value) { if (isResolved() || canContinue()) { continueResolve(value) } } config.onPause?.() }).then(() { continueFn undefined if (!isResolved()) { config.onContinue?.() } }) }重试流程在每次sleep(delay)之后也会检查canContinue()不满足则进入pause()retryer.ts。这从源码层面印证了文档中的两个结论online模式断网时连重试计时器之后的等待也会被暂停直到OnlineManager恢复在线、页面重新获得焦点且canRun()为真always模式因config.networkMode always恒为真所以永远不会暂停重试失败直接进入error状态一旦查询被取消reject 了CancelledErrorisResolved()为真continueFn不会再唤醒因此“取消后不再继续”。6.4 与 refetchOnReconnect 的区别值得再次强调暂停恢复是“继续”continue而非“重新抓取”refetch。refetchOnReconnect控制的是重连后陈旧数据是否重新抓取其默认值受 networkMode 影响见上文第三节而暂停恢复只是把之前未完成/待重试的请求续跑。二者机制不同、互相独立。七、Devtools 中的网络模式调试TanStack Query Devtools 会在查询本应抓取但因无网络连接而无法执行时将查询显示为paused状态。它同时提供一个Mock offline behavior切换按钮用于模拟离线该按钮不会真正干扰你的网络连接真实断网请在浏览器 Devtools 的 Network 面板操作它的作用是将 OnlineManager 设置为离线状态从而驱动canFetch返回false、让查询进入paused。借助这一开关你可以不拔网线就能验证三种网络模式在离线时的真实行为online进入暂停、always依旧发起、offlineFirst首次执行后按结果决定是否暂停。八、总结与选型建议三种网络模式覆盖了从“纯在线数据获取”到“完全离线本地读取”的完整光谱默认使用online面向真实网络请求的标准场景断网即暂停、联网即继续体验最稳妥本地/内存数据源使用alwaysqueryFn不依赖网络时避免无谓的暂停与重连判断离线优先应用使用offlineFirst配合 serviceWorker 缓存、HTTP 缓存或查询持久化persister使用先试缓存、失败再按在线规则处理。在 Vue 项目中只需在useQuery/useMutation选项或QueryClient全局默认中声明networkMode再结合isPending、isPaused、isFetching等响应式状态渲染界面即可完整落地离线场景的交互体验。【免费下载链接】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),仅供参考