发布时间:2026/8/24 17:51:57
Ferry normalize 包源码解析:5 个关键步骤讲透 GraphQL 数据规范化/反规范化核心原理 Ferry normalize 包源码解析5 个关键步骤讲透 GraphQL 数据规范化/反规范化核心原理【免费下载链接】ferryStream-based strongly typed GraphQL client for Dart项目地址: https://gitcode.com/gh_mirrors/fer/ferryFerry 是一个基于流Stream-based的强类型 GraphQL 客户端Dart 生态而其normalize包正是整个缓存体系的核心引擎负责把 GraphQL 响应**规范化Normalize为按实体 ID 打平的键值缓存再在需要时反规范化Denormalize**还原成嵌套的查询树。读懂这个包你就掌握了 Ferry 实现跨查询缓存共享、局部更新与引用去重的底层原理。 先搞懂两个概念规范化与反规范化GraphQL 响应天然是嵌套树查询什么样就返回什么样而现代客户端缓存的理想形态是按实体扁平存储概念输入输出作用规范化 Normalize嵌套的 GraphQL 响应 JSONdataId → 实体对象的扁平 Map同一实体只存一份天然支持缓存共享与增量更新反规范化 Denormalize扁平 Map 查询文档嵌套的响应 JSON按$ref引用递归把树拼回来规范化后的缓存长这样$ref即引用键默认由kDefaultReferenceKey定义{ Query: { pokemon: { $ref: Pokemon:25 } }, Pokemon:25: { __typename: Pokemon, name: Pikachu, id: 25 } }两个查询只要引用同一个Pokemon:25就共享同一份数据——这就是缓存高效的秘密。️ 核心源码文件速查表normalize 包代码量不大主干就是两个入口 两个递归函数 一组工具全部位于packages/normalize/lib/src/下源码文件职责normalize_operation.dart规范化总入口normalizeOperation()denormalize_operation.dart反规范化总入口denormalizeOperation()normalize_node.dart递归遍历 AST把节点写入缓存核心算法denormalize_node.dart递归遍历 AST从缓存还原节点核心算法utils/resolve_data_id.dart为实体生成唯一dataIdutils/field_key.dart生成字段名参数的组合键utils/expand_fragments.dart按__typename展开内联/命名 Fragmentutils/deep_merge.dart新旧数据深合并utils/is_dangling_reference.dart判定$ref是否指向不存在的实体policies/type_policy.dart类型级定制keyFields、根类型标记policies/field_policy.dart字段级定制keyArgs/read/mergeconfig/normalization_config.dart贯穿全程的配置上下文对外 API 统一由 normalize.dart 导出。测试文件覆盖了packages/normalize/test/下的query_fragments/、query_variables/、field_policy/、evictions/等目录是很好的行为验证素材。 规范化流水线5 个关键步骤步骤 1可选地为查询注入__typename若调用normalizeOperation()时传入addTypename: true会用AddTypenameVisitor转换查询文档见utils/add_typename_visitor.dart给每个选择集补上__typename。没有__typename的实体无法被规范化——这是整个体系的基石。步骤 2定位操作定义与根类型入口函数normalizeOperation()normalize_operation.dart先通过getOperationDefinition()从文档中找到对应操作再用resolveRootTypename()结合TypePolicy确定根类型Query/Mutation/Subscription最终组装出NormalizationConfig配置上下文。步骤 3为每个实体解析唯一 dataIdresolveDataId()utils/resolve_data_id.dart是 ID 生成器优先级非常明确TypePolicy.keyFields自定义复合主键生成TypeName:{json}形式dataIdFromObject全局自定义解析函数兜底规则id或_id字段生成经典的TypeName:id格式以上都不满足则返回null——该实体不规范化直接以嵌套形式挂在父对象下。步骤 4展开 FragmentexpandFragments()utils/expand_fragments.dart是规范化能正确处理 Fragment 的关键它依据当前实体的__typename与 Fragment 的typeCondition含possibleTypes接口/联合类型推导匹配把内联片段与命名片段的选择集深度合并成扁平的字段列表并自动剔除被skip/include跳过的字段。步骤 5normalizeNode 递归写入缓存核心算法在normalize_node.dart的normalizeNode()逻辑可以概括为列表逐项递归叶子节点无子选择集直接返回标量值对象节点先解析dataId→ 读出现有缓存 → 用FieldKey为每个字段生成带参数值的键如friends(first:1)→ 检查部分数据缺失且无read/merge策略则抛PartialDataException除非allowPartialData→ 与现有数据deepMerge()深合并 →write(dataId, merged)写入缓存并只返回{$ref: dataId}这个引用占位符。 精妙之处非根对象写入后只留引用所以同一个实体出现在 10 个查询里也只占一份内存deepMerge则保证新响应与旧缓存字段级合并实现增量更新。 反规范化如何从扁平缓存反向还原树denormalizeOperation()denormalize_operation.dart同样先解析根类型然后交给denormalizeNode()denormalize_node.dart递归还原引用识别节点含$ref键时通过config.read(dataId)取回实体本体再递归取不到即抛出DanglingReferenceException悬空引用列表容错isDanglingReference()逐个过滤悬空项配合allowDanglingReference开关决定是跳过还是抛错部分数据字段缺失且无法读取时抛PartialDataExceptionreturnPartialData: true则静默跳过handleException: true时整个操作返回null而非崩溃虚拟化字段配置了FieldPolicy.read的字段即使缓存中不存在也能通过 read 函数凭空计算出来。另外还提供denormalizeFragment()用于只针对单个 Fragment 还原数据适合细粒度的局部读取。️ 两套定制策略TypePolicy 与 FieldPolicy规范化行为可通过两级策略精细控制定义见policies/目录TypePolicy类型级keyFields指定复合主键支持嵌套子字段queryType/mutationType/subscriptionType标记根类型空keyFields可声明此类型不规范化。FieldPolicy字段级keyArgs声明哪些参数才算字段身份空列表则完全忽略参数read自定义读取逻辑merge自定义新旧数据合并——对分页列表等场景尤为重要。✅ 一句话 API 速览// 规范化把响应写入缓存 normalizeOperation(write: write, read: read, document: document, data: response, variables: variables); // 反规范化从缓存按文档还原 final data denormalizeOperation(read: read, document: document, variables: variables);write/read是解耦的函数注入上层packages/ferry_cache缓存包与packages/ferry_store存储抽象含 Hive/SQLite 持久化正是基于这两个 API 构建读写链路。 总结Ferry 的normalize包用不到 30 个文件讲清了一件事规范化 解析 dataId → 展开 Fragment → 递归 deepMerge → 写入$ref反规范化 沿 AST 递归 → 遇到$ref就查表还原。配合TypePolicy/FieldPolicy两套策略它既兼容 Relay 规范化的经典心智模型又为复合主键、虚拟化字段、部分数据等现实问题留足了扩展点。想深入验证行为建议直接跑packages/normalize/test/下的分类测试从query/simple_test.dart读起一路到field_policy/与evictions/dangling_reference_test.dart即可完整复现本文讲到的全部机制。【免费下载链接】ferryStream-based strongly typed GraphQL client for Dart项目地址: https://gitcode.com/gh_mirrors/fer/ferry创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

2026/8/24 20:13:13

Spring Boot中Jackson配置全解析:从日期处理到性能优化

1. 项目概述:为什么Spring Boot开发者绕不开Jackson?如果你用Spring Boot做过Web开发,尤其是写过RESTful API,那你肯定和Jackson打过交道。它就像一个沉默的“翻译官”,在你不知不觉中,把Java对象&#xff…

2026/8/24 20:13:13

ArcGIS矢量数据重分类:从字段计算器到实战应用

1. 从“分类”到“重分类”:一个被低估的GIS核心操作 在ArcGIS的日常数据处理中,我们经常遇到这样的场景:你手头有一份土地利用数据,其中“地类代码”字段记录了从11到83的各类用地,但你的分析只需要区分“耕地”、“林…

2026/8/24 20:08:11

Java全栈开发面试指南:从基础到架构设计

1. 项目概述 "Java全栈开发面试实录"这个项目源于我在过去三年担任技术面试官的真实经历。作为一家中型互联网公司的技术负责人,我累计面试过200Java全栈开发岗位候选人,从应届生到10年经验的老手都有接触。在这个过程中,我发现很多…

2026/8/24 0:07:22

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

2026/8/24 1:12:32

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

2026/8/24 8:17:29

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/24 1:09:25

3条命令跑通LocalAI:无GPU本地AI引擎部署

3条命令跑通LocalAI:无GPU本地AI引擎部署 【免费下载链接】LocalAI LocalAI is the open-source AI engine. Run any model - LLMs, vision, voice, image, video - on any hardware. No GPU required. 项目地址: https://gitcode.com/GitHub_Trending/lo/LocalAI…

2026/8/24 1:09:25

AI推理性能测试怎么做:MLPerf Inference完整上手指南

AI推理性能测试怎么做:MLPerf Inference完整上手指南 【免费下载链接】inference Reference implementations of MLPerf inference benchmarks 项目地址: https://gitcode.com/gh_mirrors/inf/inference 同一个模型换一张卡,速度快多少你知道吗&a…

2026/8/24 13:42:17

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/24 18:13:48

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/23 4:22:01

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…