admin- 设计并开发图片生命周期管理子系统
记录一下这一个月开发的编辑器之子系统
设计并实现了一套图片生命周期管理子系统,包含:
本地 + 远程双重去重、blob 资源自动回收、批量上传调度(带实时进度与并发控制)、异步上传期间仍可安全编辑(草稿级原子性保证)、以及带吸附机制的裁剪器(兼顾用户体验和去重稳定性)。
1. 去重:同一张图,只认一份
-
本地去重(session 级)
-
同一轮编辑里,用户反复选择同一文件,不会重复算 hash、重复上传。
-
依靠本地的
sha记录 + id 映射,避免 CPU 和带宽浪费。
-
-
远程去重(存储级)
-
同一原图 + 同一裁剪尺寸,只会在 R2 里存一份。
-
其他场景直接复用
storageKey,既省钱又省时间。
-
不论你在多少页面、多少草稿里折腾同一张图,存储端只算一份账。
2. 资源管理:用完就丢,浏览器不会越用越卡
-
所有通过
URL.createObjectURL产生的临时blob:链接,在不再需要时都会被统一URL.revokeObjectURL。 -
结合 per-draft 的 ids 收集函数,可以做到「某个草稿的临时图,全量清场」。
这让裁剪器在频繁换图、多次尝试的场景下,内存不会慢慢膨胀变成 Chrome 杀手。
3. 上传管线:聚合、进度、并发,一套齐活
-
任务聚合:多张图片会被打包进统一的上传流程,而不是一个个发散请求。
-
实时进度条:不仅有“共 N 张图已上传 M 张”,还有字节级别的
loadedBytes / totalBytes。 -
并发控制:内部已经支持限制并发数,防止把用户网络打爆(只是现在 UI 没给开关)。
写了一个小型的「上传调度器」,而不仅是
Promise.all(fetch(...))那种简单粗暴。
4. 异步上传 + 可继续编辑,但保证原子性
-
上传是完全 异步 的:用户点了 Apply crop 之后,不需要傻等,可以继续在别的字段/别的图片上编辑。
-
同时,通过草稿层的 patch + 状态机设计,保证:
-
要么这批涉及到的图片 + draft 更新整体成功;
-
要么失败时不会出现“部分字段写成新图、部分字段还是旧图”的脏状态。
-
体验上就是:你可以一边改图一边写文案,保存那一刻整个草稿是自洽的。
5. 裁剪交互:「吸附」让像素级差异不再是噩梦
-
在缩放 / 拖拽时,如果当前姿态「非常接近」默认姿态,会自动吸附回默认点:
-
scale / tx / ty 都会 snap 到 defaultPose;
-
同时把
didInteractRef置回false。
-
-
这背后有两个意义:
-
体验:用户不用为了“完全回到初始”像素级调滑块,有点偏差就自动帮你校正。
-
工程:这让去重变得可行
-
否则你会遇到那种:“明明肉眼看完全一样,但因为差了 0.0001 像素导致 params 不同” → hash/去重全部失效。
-
-
等于给交互层加了一个「人类容错层」,帮用户对齐系统的判断标准。

浙公网安备 33010602011771号