尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Apollo Client incremental 模块 API 全解析:Defer20220824Handler 与 GraphQL17Alpha9Handler 增量交付指南

Apollo Client incremental 模块 API 全解析:Defer20220824Handler 与 GraphQL17Alpha9Handler 增量交付指南 前端GraphQL【免费下载链接】apollo-clientThe industry-leading GraphQL client for TypeScript, JavaScript, React, Vue, Angular, and more. Apollo Client delivers powerful caching, intuitive APIs, and comprehensive developer tools to accelerate your app development.项目地址https://gitcode.com/gh_mirrors/ap/apollo-client点击查看免费下载导读apollo/client/incremental是 Apollo Client 中处理 GraphQL 增量交付incremental delivery的核心模块负责解析服务端通过defer与stream指令分批下发的响应并将多个分片逐步合并进查询结果。本指南以 .api-reports/api-report-incremental.api.md 公开 API 报告为骨架结合 src/incremental 目录下的真实实现系统讲解增量交付的类型体系、三种 Handler 的职责与差异、底层分片合并原理以及如何通过ApolloClient构造选项接入。读完本文你将掌握 Apollo Client 增量交付的完整类型契约并能根据服务端协议版本正确选择与配置 Handler。模块定位为什么 Apollo Client 需要独立的 incremental 子包GraphQL 的增量交付允许服务端先返回查询的主要结果再陆续下发defer延迟片段与stream流式列表对应的后续数据。客户端必须能够识别响应中哪些是普通结果、哪些是增量分片合并多个分片为完整的FormattedExecutionResult上报合并过程中的错误与 extensions。在 src/core/ApolloClient.ts 中可以看到ApolloClient构造函数接收一个incrementalHandler选项其默认值为new NotImplementedHandler()。也就是说默认情况下客户端并不处理增量交付只有显式传入 Handler 才会启用。所有与增量协议相关的类型与实现都被收敛到 src/incremental/index.ts 这个入口中导出export type { Incremental } from ./types.js; export { NotImplementedHandler } from ./handlers/notImplemented.js; export { Defer20220824Handler, Defer20220824Handler as GraphQL17Alpha2Handler, } from ./handlers/defer20220824.js; export { GraphQL17Alpha9Handler } from ./handlers/graphql17Alpha9.js;公共类型定义位于 src/incremental/types.ts三个 Handler 的实现分别位于 defer20220824.ts、graphql17Alpha9.ts 与 notImplemented.ts。核心类型契约Incremental 命名空间API 报告开头的Incremental命名空间定义了增量交付模块的全部公共类型是实现自定义 Handler 的基础接口。Path定位增量数据的路径export type Path ReadonlyArraystring | number;Path描述增量分片在结果对象中的写入位置字符串段表示对象字段名数字段表示数组索引。例如[user, friends, 3]表示result.user.friends[3]。stream分片正是借助路径末端的数字索引把流式项插入数组的正确位置。Handler增量协议的处理器接口Handler是模块中最核心的接口任何增量处理器都必须实现四个成员定义于 src/incremental/types.tsexport interface Handler Chunk extends Recordstring, unknown Recordstring, unknown, { isIncrementalResult: (result: ApolloLink.Resultany) result is Chunk; prepareRequest: (request: ApolloLink.Request) ApolloLink.Request; extractErrors: ( result: ApolloLink.Resultany ) readonly GraphQLFormattedError[] | undefined | void; startRequest: TData extends Recordstring, unknown(request: { query: DocumentNode; }) IncrementalRequestChunk, TData; }四个成员各自承担一道关键职责成员职责触发时机isIncrementalResult类型守卫判断一次ApolloLink.Result是否为该协议下的增量分片每次请求结果返回时prepareRequest改写链路请求通常用于在 HTTP context 中声明可接受的增量协议请求发出前extractErrors从分片中提取所有GraphQLFormattedError供错误策略与errorPolicy使用结果返回时startRequest为一次查询创建状态化的IncrementalRequest用于跨分片累积数据查询开始时IncrementalRequest跨分片的状态化累积器export interface IncrementalRequestChunk, TData { hasNext: boolean; handle: ( cacheData: TData | DeepPartialTData | undefined | null, chunk: Chunk ) FormattedExecutionResultTData; }IncrementalRequest是每次查询内部的状态机handle接收当前已合并的数据cacheData来自 Apollo 缓存与新的分片chunk返回合并后的完整FormattedExecutionResulthasNext指示是否还有后续分片。注意cacheData允许为undefined或null——源码注释明确指出在no-cache获取策略下会传入undefined此时实现需要回退到自身累积的旧值两个内置 Handler 都通过 this.data作为默认参数实现这一行为。StreamFieldInfo流式字段的分片边界标记export interface StreamFieldInfo { isFirstChunk: boolean; isLastChunk: boolean; }该接口标注internal用于标记某个流式数组字段当前分片是否为第一片或最后一片供内部判断数组边界在GraphQL17Alpha9Handler的streamInfoTrie 中被实际使用。Defer20220824Handler基于 2022-08-24 规范草案的实现Defer20220824Handler实现了defer/stream的历史规范提交源码注释指向 graphql-spec 仓库48cf726提交对应 HTTP 响应格式multipart/mixed;deferSpec20220824。在 API 报告中它还以别名GraphQL17Alpha2Handler导出以兼容早期 graphql-js 17 alpha 版本的命名。分片类型体系该 Handler 的分片类型由InitialResult与SubsequentResult联合构成defer20220824.tsexport type InitialResultTData Recordstring, unknown { data?: TData | null | undefined; errors?: ReadonlyArrayGraphQLFormattedError; extensions?: Recordstring, unknown; hasNext: boolean; incremental?: ReadonlyArrayIncrementalResultTData; }; export type SubsequentResultTData Recordstring, unknown { extensions?: Recordstring, unknown; hasNext: boolean; incremental?: ArrayIncrementalResultTData; };差异要点首片InitialResult携带主体data允许为null/undefined例如整段结果被错误吞掉时后续片SubsequentResult不再包含顶层data只通过incremental数组携带分片数据。incremental数组中的每个元素defer20220824.ts区分两类IncrementalDeferResultdefer分片含data、path、可选的label与errorsIncrementalStreamResultstream分片含items流式数组项、path同样支持label与errors。两者的判别在合并逻辑中通过items in incremental完成。对外方法的行为isIncrementalResult以hasNext in result作为类型守卫判断——这是 20220824 协议最直观的标记prepareRequest当查询包含defer或stream指令时向request.context.http.accept头部数组前插入multipart/mixed;deferSpec20220824defer20220824.tsextractErrors递归收集顶层errors与每个incremental分片内的errorsstartRequest返回DeferRequest实例。合并原理DeferRequest 内部状态DeferRequest私有维护errors数组、extensions对象与累积的data每次handle调用执行以下步骤defer20220824.ts用chunk.hasNext更新hasNext并将cacheData或累积值设为当前数据基底对incremental数组逐片处理items为null的流式分片将该字段路径去掉末尾数组索引加入ignoredImpossibleStreamPaths集合后续对该路径的更新一律跳过——源码注释解释这是为了防止在非空列表中出现空项时产生稀疏数组或运行时崩溃defer的data: null合并时回退为undefined避免把null覆盖进结果数组项重定位若路径末位是数字且data是数组则按startingIdx idx逐个重新定位合并保证乱序到达的流式项各就各位通过new DeepMerger({ arrayMerge: truncate }).merge(...)将分片合并进累积数据errors追加、extensions覆盖合并最终返回{ data, errors?, extensions? }其中errors与extensions仅在非空时才出现在结果中。GraphQL17Alpha9Handler面向 graphql.js 17.0.0-alpha.9 的实现GraphQL17Alpha9Handler是针对graphql包17.0.0-alpha.9增量规范对应multipart/mixed;incrementalSpecv0.2即 Apollo 增量交付规范 v0.2的处理器。相比 20220824 协议它引入了id 机制来管理多个并发的延迟分组。分片类型体系差异新协议的分片类型graphql17Alpha9.ts具有明显不同的结构export type InitialResultTData Recordstring, unknown { data: TData; errors?: ReadonlyArrayGraphQLFormattedError; pending: ReadonlyArrayPendingResult; hasNext: boolean; extensions?: Recordstring, unknown; }; export type SubsequentResultTData unknown { hasNext: boolean; pending?: ReadonlyArrayPendingResult; incremental?: ReadonlyArrayIncrementalResultTData; completed?: ReadonlyArrayCompletedResult; extensions?: Recordstring, unknown; };与 20220824 版本相比的关键变化新增pending数组在首片中声明哪些延迟分组已就绪PendingResult含id、path与可选label新增completed数组后续片中用于标记已完成的分组CompletedResult含id与可选errors处理stream截断与defer收尾每个IncrementalDeferResult/IncrementalStreamResult均携带id字段增量数据改用subPath相对路径替代绝对path实际写入位置由pending.path.concat(incremental.subPath ?? [])计算得出。GraphQL17Alpha9Handler的四个方法在 API 报告中均被标注internal deprecated但类本身为public意味着方法是内部实现细节公开的是以Incremental.Handler接口约定的能力。合并原理IncrementalRequest 的流式定位策略IncrementalRequestgraphql17Alpha9.ts是该协议下的状态累积器其实现亮点包括streamPositions映射以pending.id为键记录下一次流式项的插入位置替代依赖数组长度计算位置的朴素做法——源码注释说明缓存中的数组引用可能被后续分片修改因此必须显式追踪位置避免覆盖缓存更新稀疏数组合并流式分片到达时构造parent[i streamPositions[id]] items[i]的稀疏数组再由DeepMerger依据Object.keys正确落位流式信息 Trie借助wry/trie构建StreamInfoTrie跟踪每个流式数组的isFirstChunk/isLastChunk状态completed 处理分组完成时若存在streamPositions记录则将对应数组按位置slice截断以处理仅含hasNext: falsecompleted的收尾分片并从pending中删除该分组extensions 透传当 Trie 仍持有强引用时在结果 extensions 中注入以streamInfoSymbol为键的WeakRef指向StreamInfoTrieQueryInfo通过引用相等性判断触发最终缓存写入同时WeakRef避免长期持有内存。extractErrors还额外处理completed分组中的错误而 20220824 版本没有该路径。NotImplementedHandler未配置处理器时的兜底行为NotImplementedHandler是ApolloClient的默认incrementalHandlerApolloClient.ts其isIncrementalResult恒返回falsestartRequest置为undefined as any该路径在运行时不可达而prepareRequest是关键防线notImplemented.tsprepareRequest(request: ApolloLink.Request) { invariant( !hasDirectives([defer, stream], request.query), defer and stream are not supported without specifying an incremental handler. Please pass a handler as the incrementalHandler option to the ApolloClient constructor. ); return request; }即一旦查询中出现defer或stream指令而用户未配置 Handler客户端会在请求准备阶段抛出 invariant 错误提示显式传入处理器。这就是默认不支持增量交付的设计意图——协议版本必须由使用者按服务端能力显式声明。实战接入如何选择与配置 Handler在 ApolloClient 构造函数中启用在 src/core/ApolloClient.ts 中incrementalHandler的声明类型为Incremental.Handlerany。实际接入方式如下import { ApolloClient, InMemoryCache, } from apollo/client; import { Defer20220824Handler, GraphQL17Alpha9Handler, } from apollo/client/incremental; // 服务端支持 incrementalSpecv0.2graphql-js 17 alpha 系列时 const client new ApolloClient({ uri: https://api.example.com/graphql, cache: new InMemoryCache(), incrementalHandler: new GraphQL17Alpha9Handler(), }); // 服务端基于 2022-08-24 defer 规范草案时 const clientLegacy new ApolloClient({ uri: https://api.example.com/graphql, cache: new InMemoryCache(), incrementalHandler: new Defer20220824Handler(), });选择依据GraphQL17Alpha9Handler对应multipart/mixed;incrementalSpecv0.2适用于支持pending/completed/id机制的新版服务端Defer20220824Handler对应multipart/mixed;deferSpec20220824适用于旧版defer/stream草案实现并以GraphQL17Alpha2Handler别名兼容早期 graphql-js 命名NotImplementedHandler不显式传入时的默认值遇到defer/stream会立即报错提示。运行时接入链配置生效后Handler 会贯穿查询全生命周期QueryManager在请求前调用prepareRequestQueryManager.ts为含defer/stream指令的查询注入正确的Accept头结果返回时QueryInfo调用isIncrementalResult判断是否增量分片若是则调用startRequest创建状态化累积器QueryInfo.ts后续每个分片经由IncrementalRequest.handle合并hasNext: false表示流结束。类型层面的接入HKT 类型覆盖API 报告中的每个 Handler 都声明了TypeOverrides接口如interface TypeOverrides { AdditionalApolloLinkResultTypes: Defer20220824Result; }Defer20220824Result、GraphQL17Alpha9Result、NotImplementedResult均继承HKT高阶类型来自 apollo/client/utilities通过arg1/arg2表示TData/TExtensions两个类型参数、return表示分片类型。这套机制让 TypeScript 可以将增量分片类型注入ApolloLink的结果类型系统使defer/stream响应在类型层面可追踪。若需为自定义协议编写 Handler实现Incremental.Handler并声明对应的TypeOverrides即可获得同样的类型推断支持。质量保障测试如何验证两个协议仓库为两个 Handler 各维护了独立且详尽的测试套件src/incremental/handlers/tests并复用了大量 graphql-js 官方测试用例defer20220824/defer.test.ts覆盖延迟标量片段、if参数禁用、顶层字段延迟、延迟片段内嵌套延迟、延迟片段抛错、非空错误冒泡、多分片顺序等defer20220824/stream.test.ts覆盖列表流式、initialCount默认值、多维列表、Promise 列表、async iterable、非空项返回null、跨延迟边界的null过滤等graphql17Alpha9/defer.test.ts进一步覆盖 inline fragment 延迟、不同 label 的延迟分组分别下发、同对象多次 defer 去重、跨 defer 边界 null 冒泡、结果不可合并时过滤分片等graphql17Alpha9/stream.test.ts验证新协议下的流式行为与位置定位。此外src/core/tests下还有大量端到端集成测试如client.watchQuery/defer20220824.test.ts、client.watchQuery/streamGraphQL17Alpha9.test.ts等每个用例都以incrementalHandler: new Defer20220824Handler()或new GraphQL17Alpha9Handler()配置客户端验证 Handler 与watchQuery、useQuery、useSuspenseQuery、useBackgroundQuery等 API 组合下的真实行为。阅读这些测试是理解两种协议差异最快的路径。小结apollo/client/incremental模块以协议可插拔为设计核心Incremental.Handler抽象出协议识别、请求改写、错误提取与分片累积四步能力Defer20220824Handler与GraphQL17Alpha9Handler分别是旧版草案与新版 v0.2 规范的两套落地实现前者通过path定位、后者通过idpending/completed管理多个并发延迟分组NotImplementedHandler则保证未显式配置时行为可预期。接入时只需在ApolloClient构造函数中根据服务端协议选择对应 Handler即可让defer/stream的增量响应被正确、完整地合并进查询结果。赞分享前端GraphQL【免费下载链接】apollo-clientThe industry-leading GraphQL client for TypeScript, JavaScript, React, Vue, Angular, and more. Apollo Client delivers powerful caching, intuitive APIs, and comprehensive developer tools to accelerate your app development.项目地址https://gitcode.com/gh_mirrors/ap/apollo-client点击查看免费下载相关推荐Apollo Client 错误体系全解析apollo/client/errors 模块 API 深度指南Apollo Client 错误体系全解析apollo/client/errors 模块 API 深度指南 Apollo Client 将运行时可能遇到的错前端GraphQLApollo Client HttpLink 模块完全指南从 API 报告到源码级解析Apollo Client HttpLink 模块完全指南从 API 报告到源码级解析 本指南以 Apollo Client 仓库中的公开 API 报告 .a前端GraphQLApollo Client 4.0 被移除 API 全解析apollo/client/v4-migration 迁移清单与 Removals 分类指南Apollo Client 4.0 被移除 API 全解析 apollo/client/v4 migration 迁移清单与 Removals 分类指南 导前端GraphQL上一篇Apache Airflow 插件系统完全指南从 plugins 目录到 FastAPI、React App 与视图扩展下一篇Yuxi-Know企业级部署Docker Compose最佳实践指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表