@libeilong/model-manager
v0.1.16
Published
一个高性能、内存安全且类型友好的 TypeScript 领域模型管理库。专为复杂的前端应用设计,支持 **自动内存管理 (WeakRef)**、**响应式框架集成 (Vue/MobX)** 以及 **精细化的数据合并策略**。
Downloads
80
Readme
Model Manager
一个高性能、内存安全且类型友好的 TypeScript 领域模型管理库。专为复杂的前端应用设计,支持 自动内存管理 (WeakRef)、响应式框架集成 (Vue/MobX) 以及 精细化的数据合并策略。
✨ 特性
- 🚀 内存安全:基于
WeakRef和FinalizationRegistry实现自动垃圾回收,防止内存泄漏。 - ⚡️ 响应式友好:支持 原地修改 (In-Place Mutation),完美适配 Vue (Reactive/Ref) 和 MobX 等响应式系统,保持引用稳定性。
- 🔄 智能合并:提供
replace、merge、append多种策略处理嵌套关系和数组更新。 - 🔗 关系管理:轻松定义一对一、一对多关系,自动处理循环引用和延迟加载。
- 💎 类型增强:强大的 TypeScript 类型推导,自动生成
create方法的输入类型定义。 - 📦 序列化控制:支持多种序列化策略(仅主键、完整对象、混合模式),灵活应对 API 提交需求。
📦 安装
npm install model-manager
# 或者
yarn add model-manager🚀 快速开始
1. 定义模型
你可以传入自定义的基类(如 Vue 的响应式基类),库会自动混入(Mixin)模型管理能力。
import { createBaseModel, Model, PrimaryKey, Relation, PK_PROP } from 'model-manager'
// 模拟一个响应式基类 (适配 Vue/MobX 等)
class ReactiveBase {}
// 1. 创建基础模型,混入能力
@Model({ cache: false, serialization: 'hybrid' })
class BaseModel<T = 'id'> extends createBaseModel(ReactiveBase) {
// 声明 PK_PROP 用于类型推导窄化
declare [PK_PROP]: T
@PrimaryKey()
id: number = 0
createdAt: Date = new Date()
}
// 2. 定义 User 模型
@Model({ cache: true, mergeOnCacheHit: true, serialization: 'pk' })
class User extends BaseModel {
name: string = ''
email?: string
// 定义一对多关系,第二个参数 true 表示数组
@Relation(() => Order, true)
orders: Order[] = []
// 普通数组(非领域模型)
posts: Array<{ id: number; title: string }> = []
}
// 3. 定义 Order 模型
@Model({ cache: true, serialization: 'object' })
class Order extends BaseModel<'on'> {
// 自定义主键字段名
@PrimaryKey()
on: string = ''
title: string = ''
price?: number
// 定义一对一关系
@Relation(() => User)
creator!: User
}2. 使用模型
// 创建数据
const user = User.create({
id: 1,
name: 'Alice',
orders: [{ on: 'ORD-001', title: 'Book', price: 100 }],
})
// user.orders[0] 已经是 Order 类的实例
console.log(user.orders[0] instanceof Order) // true
// 再次创建相同 ID 的 User (缓存命中)
const user2 = User.create({
id: 1,
name: 'Alice Updated', // mergeOnCacheHit: true,属性会自动更新
})
console.log(user === user2) // true,引用完全相同
console.log(user.name) // "Alice Updated",实现原地更新📖 API 文档
装饰器
@Model(options: ModelOptions)
配置类的全局行为。
| 选项 | 类型 | 说明 | 默认值 |
| :---------------- | :----------------------------- | :------------------------------------------------------- | :--------- |
| cache | boolean | 是否启用实例缓存 | false |
| cacheStrategy | 'weak' \| 'strong' | 缓存策略。weak 使用弱引用(推荐),strong 为强引用。 | 'weak' |
| serialization | 'hybrid' \| 'pk' \| 'object' | 默认序列化策略。 | 'hybrid' |
| mergeOnCacheHit | boolean | 当 create 命中缓存时,是否自动合并新数据。 | false |
| primaryKey | string | 主键字段名(通常建议使用 @PrimaryKey 装饰器)。 | - |
@PrimaryKey()
标记类的属性为主键。库依赖主键进行缓存去重。
@Relation(targetGetter, isArray?, config?)
定义模型间的关联关系。
targetGetter:() => Class。使用函数返回类,解决循环引用问题。isArray:boolean。是否为数组关系。config: 序列化配置等。
核心方法 (Mixin)
继承 createBaseModel 后,你的类将获得以下静态方法和实例方法。
静态方法
static create(data, options?)创建或获取模型实例。如果缓存中存在且开启了缓存,则返回已有实例。data: 强类型的输入对象(支持递归嵌套)。options.merge: 强制覆盖类配置的合并行为。
static createReference(pk)仅通过主键创建一个“引用状态”的实例(标记为isLoaded: false),常用于延迟加载场景。static find(pk)从缓存中查找实例。
实例方法
merge(data, options?)增量合并数据到当前实例。这是实现响应式更新的核心。user.merge( { name: 'Bob' }, { // 数组合并策略: // 'replace' (默认): 以新数组为准,同步更新内容 // 'merge': 保留本地多余项,合并新项 // 'append': 追加新项 arrayStrategy: 'replace', }, )serialize(options?)将模型转换为普通 JSON 对象。- 支持处理循环引用(自动降级为主键)。
- 根据
@Model配置决定关系字段是输出 ID 还是完整对象。
load(options?)触发数据加载。需要用户在类上实现静态_fetchData方法。// 在类定义中实现 static async _fetchData(pk, context) { return await api.getUser(pk); } // 调用 await user.load();
💡 核心概念与最佳实践
1. 响应式集成 (Vue/MobX)
本库的设计初衷之一是配合现代前端框架。
- 原地修改 (In-Place Mutation):
merge方法会直接修改对象属性,而不是替换对象引用。 - 基类继承:通过
createBaseModel(Base),你可以传入Vue的类或其他基类,使得所有生成的 Model 实例天然具备响应式能力。
2. 内存管理机制
为了防止随着应用运行 Model 实例无限堆积,默认使用 WeakRef + FinalizationRegistry。
- 当 UI 组件卸载,不再持有 Model 引用时,GC 会自动回收 Model。
- 库会自动监听到回收事件,并从内部缓存 Map 中清理对应的 Key,防止内存泄漏。
3. 数据合并策略 (replace vs merge)
在处理数组关系时(例如更新 user.orders):
replace(默认):视为“同步”。后端返回的列表就是最新状态。本地多余的项会被移除,存在的项会原地更新属性,新的项会追加。merge:视为“合并”。保留本地所有项,并把后端返回的数据更新进去。适用于“加载更多”或“增量推送”场景。
