0
0

给前端 AI 文件预览加大文件保护时,我会先把解析和渲染拆开

最近在做一个前端 AI 工作台,用户会把会议记录、日志、CSV、Markdown 拖进页面,让 AI 先预览再提取信息。早期实现很直接:拿到 File 后一次性读成文本,塞进状态,再交给解析函数。样本小的时候无感,几十 MB 日志一来,主线程卡顿、预览白屏、取消按钮失效,连续上传后内存还会涨。

前端 AI 文件预览从文件门禁到 Worker 解析再到资源清理的流程示意图

原创示意图:把文件选择、大小门禁、流式读取、Worker 解析、预览缓存和对象 URL 清理放进同一条可取消链路。 来源:Codex image generation

问题背景

MDN 的 File API 文档说明,Web 应用可以通过文件选择控件或拖放拿到 File 对象;Blob 的 stream() 又能接入流式读取。能力本身很方便,但大小上限、解析位置、取消时机和资源释放都要由业务自己定义。我给这条链路定了三个目标:预览先出来,重解析放后台,用户随时能取消。

踩坑和关键难点

第一个坑是读取和渲染绑在一起。文件一大,解析函数会占住主线程,loading 还没绘制页面已经卡住。Web Workers 适合接管重解析、分块扫描和格式探测,主线程只处理选择、进度、取消和可见预览。

第二个坑是一次性读取全文。很多预览只需要前几千行、前几页或前几个结构块。ReadableStream 可以按 chunk 推进,先产出首屏预览,再继续做完整索引。AI 摘要、embedding 或结构化抽取等后续动作,应该等用户确认预览后再启动。

第三个坑是清理靠运气。图片、PDF 或二进制附件常用 URL.createObjectURL() 做本地预览,如果替换文件、关闭面板或取消任务时没有调用 URL.revokeObjectURL(),短时间看不出问题,长时间使用会出现内存压力。

解决思路

我把链路拆成六层:File Picker 拿文件;Gate 做大小、类型和 MIME 兜底判断;Stream Reader 分块读取并回传进度;Worker Parser 做重解析和取消检查;Preview Cache 只存首屏轻量数据;Cleanup 统一处理 object URL、Worker、临时缓存和错误状态。

每个文件进入时生成 fileJobId,记录 name、size、type、lastModified 和本地 hash 摘要。主线程发给 Worker 的消息只带必要字段和 chunk,不传 DOM 引用,也不把完整内容塞进全局状态。Worker 回传 progress、previewPatch 或 errorCode,主线程只更新可见区域。

关键步骤

第一步是建立硬门禁。文本类文件限制单文件大小和批次总量,未知类型只给安全预览,不自动进入 AI 处理。门禁失败时返回原因和建议动作,减少反复重试。

第二步是做可取消协议。主线程保存 AbortController 和 workerJobId,用户换文件或关闭面板时先发 cancel,再终止未响应的 Worker。Worker 每处理一段都检查取消标记。

第三步是做清理账本。每个 fileJobId 记录创建过的 object URL、临时缓存 key、Worker 实例和定时器。完成、失败、取消、组件卸载都走同一个 cleanup 函数。

可复用经验

文件预览看起来是 UI 小功能,实际会影响 AI 工作台稳定性。我的经验是把文件入口当成工作流:入口有门禁,读取可分块,解析进 Worker,预览保留轻量状态,资源释放有账本。后面接 RAG 文档导入、日志分析、CSV 问答或 Electron 本地文件助手,都可以沿用这条边界,先让页面稳住,再让 AI 做重任务。

主要来源

MDN File API

MDN Web Workers API

MDN ReadableStream

MDN URL.createObjectURL

MDN URL.revokeObjectURL

评论