ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Amplify DataStore 生命周期事件解析:Start、Stop、Clear 的完整工作流程

Amplify DataStore 生命周期事件解析:Start、Stop、Clear 的完整工作流程 前端后端移动开发【免费下载链接】amplify-jsA declarative JavaScript library for application development using cloud services.项目地址https://gitcode.com/gh_mirrors/am/amplify-js点击查看免费下载本指南以 packages/datastore/docs/datastore-lifecycle-events.md 为骨架深入剖析 Amplify DataStore 的三大生命周期事件Start初始化、Stop停止同步与Clear清空数据。你将掌握 DataStore 从启动到就绪的七个内部阶段、Schema 迁移与 Outbox 出站队列的处理顺序以及如何用 Stop/Clear 管理应用运行时的同步行为并配合仓库源码理解每一步的底层实现。Amplify DataStore 是 AWS Amplify 提供的一种声明式离线持久化与在线同步框架。与普通存储 API 不同DataStore 内置了一套复杂的生命周期管理本地 IndexedDB 存储、GraphQL 同步引擎、变更队列Outbox、订阅缓冲等组件在其生命周期中按严格顺序协同工作。理解这些生命周期事件是正确使用 DataStore、排查同步问题、实现选择性同步selective sync的必备前提。一、DataStore 初始化Start七个关键阶段理解 DataStore 如何启动是理解 DataStore 底层工作方式的核心。在高层面上启动 DataStore 会对每个模型按顺序执行以下操作Init Schema初始化 SchemaInit the Storage Engine初始化存储引擎Migrate schema changes迁移 Schema 变更Sync Engine Operations同步引擎操作Empty the Outbox / processes the mutation queue清空出站队列/处理变更队列Begin processing the subscription buffer开始处理订阅缓冲DataStore is now in ready stateDataStore 进入就绪状态需要明确的是可以调用DataStore.start()主动启动 DataStore否则调用任意方法query、save、delete、observe都会隐式触发启动流程。导入模型时DataStore 会消费schema.js并创建对应的 IndexedDB store。在 packages/datastore/src/datastore/datastore.ts 中start方法被封装在runningProcesses后台进程管理器中执行并将状态机推进为DataStoreState.Starting。首次调用时它创建一个initializedPromise 并通过initResolve记录 resolve 回调后续调用会等待同一个 Promise从而保证幂等。这与文档描述的「懒启动」首次交互触发启动完全对应。1.1 Init Schema1.1首先调用initSchema实现位于 datastore.ts。1.2随后 Amplify Codegen 依据用户定义的数据模型生成schema.js。1.3DataStore 消费schema.js将其解析为内部的Schema结构包含 namespaces、models、enums、nonModels、relationships 等元数据。在源码中initSchema完成的是数据模型声明到运行时元数据的转换它注册非模型类registerNonModelClass、建立模型关系与主键字段信息establishRelationAndKeys、extractPrimaryKeyFieldNames等这些元数据后续会驱动存储引擎建表与同步引擎生成 GraphQL 操作。1.2 Init the Storage Engine初始化存储引擎2.1初始化存储适配器Adapter。DataStore 默认在浏览器环境使用 IndexedDB 适配器在 React Native 等环境则使用对应适配器如 AsyncStorage 适配器具体由 packages/datastore/src/storage/adapter/getDefaultAdapter/index.ts 决定。2.2如果本地数据库不存在则创建它。2.3适配器的setUp方法会调用数据库的init方法。以 IndexedDBAdapter.ts 为例initDb使用idb.openDB打开数据库并在upgrade回调中为每个 namespace 下的每个模型创建对应的 Object StorecreateObjectStoreForModel。2.4建立模型间的关系Relations。值得注意的是在用户与 DataStore 发生第一次交互之前这些初始化动作都不会真正执行——一切都被惰性地推迟到首次操作。在start()的源码中这一阶段表现为this.storage new Storage(...)与await this.storage.init()其中StorageExclusiveStorage是存储引擎的封装层负责串行化所有底层读写packages/datastore/src/storage/storage.ts。1.3 Migrate schema changes迁移 Schema 变更如果需要详见 schema-changes.md。如果用户更新了 Schema此阶段会执行数据迁移。从源码来看这一步的实际行为由checkSchemaVersion实现datastore.ts它在存储引擎初始化之后、同步引擎初始化之前执行schema.js即用户生成的模型文件位于src/models/schema.js中携带一个版本哈希version hash。该哈希会与本地数据库中Settings表里存储的版本哈希进行比对。Settings 表中的记录形如{ id: 01FYABF3DMBZZJ46W1CC214NH2, key: schemaVersion, value: \4401034582a70c60713e1f7f9da3b752\ }checkSchemaVersion查询Setting模型中key schemaVersion的记录比较存储值是否与当前schema.version一致若版本不同则调用s.clear(false)直接清空整个本地数据库随后执行一次完整同步full sync若尚无该记录则写入当前版本哈希。也就是说Amplify 对 Schema 变更的策略是「版本不一致即全量清库并重新全量同步」而不是做增量迁移。这也是为什么修改数据模型后首次启动 DataStore 会观察到本地数据被清空、重新拉取云端数据的原因。1.4 Sync Engine Operations同步引擎操作同步引擎SyncEngine是整个 DataStore 在线同步能力的核心其实现位于 packages/datastore/src/sync/index.ts。4.1 实例化 Sync Engine源码中this.sync new SyncEngine(schema, namespaceResolver, syncClasses, userClasses, this.storage, ...)datastore.ts。只有配置了 GraphQL endpoint即aws_appsync_graphqlEndpoint时Sync Engine 才会被实例化——这意味着后端已经完成预置provisioned。否则DataStore 进入仅本地模式local-only mode此时日志会提示Data wont be synchronized. No GraphQL endpoint configured。注意在此阶段订阅缓冲buffer还不会被处理。每个模型会建立三个订阅subscriptioncreate、update、delete。4.2 启动 Sync EnginesyncSubscription this.sync.start({ fullSyncInterval }).subscribe({...})datastore.ts。这里fullSyncInterval由用户的配置参数单位为分钟乘以1000 * 60换算为毫秒传入。4.2.1 订阅 Sync Engine该订阅产生的事件会以Hub 事件的形式派发Hub.dispatch(datastore, { event: type, data })供开发者监听。当就绪时调用initResolve()将 DataStore 的启动 Promise 置为完成。若认证未通过unauthorizedDataStore 仍会继续工作——因为可能存在公开可读的模型publicly readable models。若发生校验错误validation errorDataStore 的同步会整体中断。没有订阅DataStore 无法工作前提是存在 GraphQL endpoint。订阅是唯一能把远端数据更新到本地 store 的组件如果更新到来时同步尚未完成这些消息会被缓冲待同步完成后统一处理。此阶段还会准备 sync predicates同步谓词用于选择性同步类似于适配器建立时的谓词设置。在 sync/index.ts 中定义了完整的ControlMessage枚举这些消息即通过 Hub 以 DataStore 事件形式暴露给开发者export enum ControlMessage { SYNC_ENGINE_STORAGE_SUBSCRIBED storageSubscribed, SYNC_ENGINE_SUBSCRIPTIONS_ESTABLISHED subscriptionsEstablished, SYNC_ENGINE_SYNC_QUERIES_STARTED syncQueriesStarted, SYNC_ENGINE_SYNC_QUERIES_READY syncQueriesReady, SYNC_ENGINE_MODEL_SYNCED modelSynced, SYNC_ENGINE_OUTBOX_MUTATION_ENQUEUED outboxMutationEnqueued, SYNC_ENGINE_OUTBOX_MUTATION_PROCESSED outboxMutationProcessed, SYNC_ENGINE_OUTBOX_STATUS outboxStatus, SYNC_ENGINE_NETWORK_STATUS networkStatus, SYNC_ENGINE_READY ready, }4.2.2 订阅 DataStore 网络连接状态通过this.datastoreConnectivity.status().subscribedatastore.ts 引用自 packages/datastore/src/sync/datastoreConnectivity.ts订阅一个监听网络可达性的 Amplify Core 组件DataStoreConnectivity。之所以在此订阅网络状态是因为 DataStore 需要按网络状态启停同步过程离线时断开 WebSocket 并停止同步恢复在线时重新建立 WebSocket并继续执行 base sync / delta sync。同时Sync Engine 会订阅 Storage Engine每一次本地写入都可能需要被翻译为一条 outbox 变更mutation。Storage Engine 是 DataStore 的本地真相源local source of truth其余组件都在观察它。4.2.3 在线状态下运行同步查询Sync Queries说明DataStore 会对待同步的数据执行拓扑排序topological sort——先同步子模型这样查询父模型时子模型已经就绪同时对相互无依赖的模型使用并行化优化以提升首次同步速度。同步查询是用于初始灌入hydrate本地 store的 GraphQL 查询。首次运行应用时DataStore 会对 DynamoDB 执行一次scan最多每个表 10,000 条记录来填充本地 store若启用了选择性同步selective sync则执行query而非 scan。初始同步查询之后的变更都通过订阅推送进来。存在两种同步机制Base sync基础同步拉取所有记录直到 total sync 值。Delta sync增量同步每个模型对应一个表每个 DataStore store 对应一个 delta sync 表。AppSync 最终决定执行 base sync 还是 delta sync客户端在同步查询中附带lastSync参数服务端比较差异后做出裁决。所有 delta sync 表记录都有TTL过期时间——要查看 TTL可以在 AppSync Console 中打开「Update Data Source」查看。在 sync/index.ts 中同步查询处理器SyncProcessor位于 packages/datastore/src/sync/processors/sync.ts负责执行 base/delta 查询并在完成后发出SYNC_ENGINE_SYNC_QUERIES_READY消息。此外DataStore 在 Node.js 环境与非 Node 环境的「就绪判定」略有不同datastore.tsconst readyType isNode() ? ControlMessage.SYNC_ENGINE_SYNC_QUERIES_READY : ControlMessage.SYNC_ENGINE_STORAGE_SUBSCRIBED;在Node.js中需要等待同步查询完成SYNC_ENGINE_SYNC_QUERIES_READY才能返回数据避免首次查询返回空数组。在浏览器 / React Native中一旦订阅建立SYNC_ENGINE_STORAGE_SUBSCRIBED即可开始返回数据。1.5 Empty the Outbox / 处理变更队列mutation queue典型场景离线状态下执行变更时记录被追加到出站队列Outbox中。一旦恢复网络连接DataStore 会**一条一条ONE BY ONE**地发送这些变更。注意Amplify 未向用户暴露任何批处理 APIbatch API——变更只能逐个发送。每条变更事件都有唯一的id。同步查询会先于变更发送被应用syncs get applied before mutations are sent即先完成数据灌入再按序发送本地离线变更。Outbox 的底层实现位于 packages/datastore/src/sync/outbox.ts变更处理器位于 packages/datastore/src/sync/processors/mutation.ts。当网络恢复时MutationProcessor会从 Outbox 中取出排队的MutationEvent逐个执行 GraphQL mutation并在此过程中发出SYNC_ENGINE_OUTBOX_MUTATION_ENQUEUED、SYNC_ENGINE_OUTBOX_MUTATION_PROCESSED、SYNC_ENGINE_OUTBOX_STATUS等 ControlMessage。1.6 Begin processing the subscription buffer开始处理订阅缓冲如果在初始化订阅、执行同步查询或处理变更队列的任何阶段收到了订阅消息DataStore 会先将这些订阅消息**缓冲buffer**起来直到上述所有步骤完成。只有处理完变更队列后才会开始处理订阅缓冲——保证最终一致性的数据落库顺序先本地、再云端历史、最后实时增量。订阅处理器位于 packages/datastore/src/sync/processors/subscription.ts负责为每个模型建立create/update/delete三条订阅通道并通过 packages/datastore/src/sync/merger.ts 中的ModelMerger将远端数据合并回本地 store。1.7 DataStore 进入 ready 状态以上所有步骤完成后start()内部会await this.initialized随后将状态推进为DataStoreState.Runningdatastore.ts。此时 DataStore 处于就绪状态可以正常执行query、save、delete、observe等操作并持续通过订阅接收远端变更。二、Stop停止同步DataStore.stop()用于停止 DataStore 的同步过程会关闭实时订阅连接real-time subscription connection适用于应用不再关心数据更新的场景例如应用即将关闭、页面离开后台。典型用法是在应用即将关闭前调用DataStore.stop()。一个高级用法强制在运行时重新求值同步表达式sync expressions——调用stop()之后再调用start()即可让syncExpressions在新条件下重新生效从而在运行时动态调整选择性同步策略。从源码看datastore.tsstop()会执行将状态机置为DataStoreState.Stopping通过await this.runningProcesses.close()优雅关闭所有后台进程取消syncSubscription若未关闭调用await this.sync.stop()停止 Sync Engine将initialized置为undefined使得下一次start()或隐式启动会重新初始化、将sync置为undefined重新打开进程管理器状态回到DataStoreState.NotRunning。注意stop()不会清除本地数据本地 store 中的数据仍然保留重新启动后会继续增量同步。三、Clear清空本地数据DataStore.clear()用于清除 DataStore 的本地数据。清除之后DataStore 会需要一次**完整同步full sync而非 delta sync**才能重新用云端数据填充本地 store。从源码看datastore.tsclear()是一个比stop()更彻底的操作校验 Schema 已初始化将状态机置为DataStoreState.Clearing关闭所有后台进程runningProcesses.close()若 storage 尚未初始化则先创建并初始化 Storage以便在不完整启动的情况下也能清库取消syncSubscription调用await this.sync.stop()停止 Sync Engine调用await this.storage.clear()清空本地存储将initialized、storage、sync全部置为undefined并重置syncPredicates重新打开进程管理器状态回到DataStoreState.NotRunning。源码注释特别指出clear()之后必须重新初始化可以显式调用start()也可以调用任何会隐式启动 DataStore 的方法如query()、save()、delete()。清库会删除本地所有模型数据、Schema 元数据与其他初始化细节。正因为clear()会移除本地数据并触发全量同步它也常用于调试或重置用户本地状态的场景。结合前文checkSchemaVersion的逻辑当 Schema 版本变化时系统内部也会调用s.clear(false)完成同样的「清库 全量同步」过程——所以你可以把 Schema 变更后的首启行为理解为一次自动触发的 Clear。四、生命周期事件的工程实践要点将三个生命周期事件放入实际工程场景可以总结出如下最佳实践场景推荐操作效果应用启动 / 页面需要数据调用query等操作或显式DataStore.start()懒启动或主动启动完成七阶段初始化应用即将关闭、离开同步场景DataStore.stop()关闭订阅与同步保留本地数据运行时切换选择性同步条件stop()后立即start()重新求值 syncExpressions重跑同步重置用户本地数据 / 调试DataStore.clear()清空本地 store后续触发完整同步修改了数据模型Schema无需手动操作checkSchemaVersion检测版本不一致自动清库并全量同步几个容易踩坑的提醒均有源码依据无 GraphQL endpoint 时不会实例化 SyncEnginedatastore.ts——DataStore 退化为纯本地模式注意配置Amplify.configure(awsconfig)中的aws_appsync_graphqlEndpoint。同步引擎对校验错误不宽容——发生 validation error 时同步会整体中断因此在 DataStore 初始化阶段监听 Hub 事件、捕获错误十分关键。Outbox 变更逐条发送、无批量 API——离线期间积累大量变更时恢复网络后的同步耗时与变更数量线性相关需要合理设计离线写入策略。订阅是远端数据进入本地 store 的唯一通道——这也是为什么离线场景下必须依赖订阅恢复后的缓冲机制来保证数据最终一致。如果希望深入代码研究建议按以下顺序阅读仓库源码生命周期主控packages/datastore/src/datastore/datastore.tsstart/stop/clear/checkSchemaVersion同步引擎与事件枚举packages/datastore/src/sync/index.ts存储引擎与 IndexedDB 建表packages/datastore/src/storage/storage.ts、packages/datastore/src/storage/adapter/IndexedDBAdapter.ts网络状态监测packages/datastore/src/sync/datastoreConnectivity.ts离线变更队列packages/datastore/src/sync/outbox.ts数据处理管线packages/datastore/src/sync/processors/sync.ts、packages/datastore/src/sync/processors/mutation.ts、packages/datastore/src/sync/processors/subscription.ts五、总结DataStore 的生命周期是一个精心编排的状态机从 Schema 初始化、存储引擎建库、Schema 版本校验到同步引擎的订阅建立、网络监控、初始同步查询再到 Outbox 清空与订阅缓冲处理最终进入就绪状态。stop()与clear()则在运行期为开发者提供了「优雅下线」与「本地重置」两种控制手段。理解这七阶段流程与两类运行时操作既能帮助你预判 DataStore 在首次启动、Schema 升级、网络切换、离线变更回放等场景下的实际行为也是定位同步异常与优化选择性同步策略的基础。赞分享前端后端移动开发【免费下载链接】amplify-jsA declarative JavaScript library for application development using cloud services.项目地址https://gitcode.com/gh_mirrors/am/amplify-js点击查看免费下载相关推荐掌握Vue.draggable.next事件系统从start到end的完整交互指南掌握Vue.draggable.next事件系统从start到end的完整交互指南 Vue.draggable.next是基于Sortable.js的VueUI组件前端Hedera常见问题解答解决Unity常春藤插件安装、生长、渲染中的10大难题Hedera常见问题解答解决Unity常春藤插件安装、生长、渲染中的10大难题 Hedera是一个强大的Unity编辑器插件让你能够在Unity中实时绘制3dcg快速上手教程一行命令让Claude Code不再误删你的项目文件dcg快速上手教程一行命令让Claude Code不再误删你的项目文件 如果你正在用 Claude Code 这类 AI 编程智能体写代码那么你一定听说过AI 安全治理应用安全CLI开发工具上一篇不规则时间序列预训练实战指南基于 irregular_timeseries_pretraining 的自监督预训练与下游微调下一篇为什么选择th_PP-OCRv5_mobile_rec_onnx探索泰语OCR识别的5大核心优势创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表