react fiber 是渲染协调器,不参与文件上传;其作用是将渲染任务分片、可中断执行,避免阻塞主线程,从而保障上传过程中 ui 的响应性。

React Fiber 本身不参与文件上传逻辑,它只是 React 的渲染协调器;想用 Fiber 实现大文件分片上传,本质是误解了 Fiber 的职责边界——你真正需要的是在 Fiber 调度下「不阻塞 UI」地执行切片、哈希、上传等 CPU/IO 密集操作。
为什么不能直接“用 Fiber 实现上传”
Fiber 是 React 内部的 reconciler 架构,不是协程或线程抽象。它不提供 spawn、yield 或底层 I/O 控制能力。所谓“Fiber 支持并发”,是指 React 能把更新任务拆成可中断的小单元,交还主线程控制权,但它不会帮你读文件、算 MD5、发请求。
- 误以为
useTransition或startTransition能让file.slice()变快 —— 实际上它只影响 state 更新的优先级,不影响 Blob 操作本身 - 试图在
useEffect中同步调用SparkMD5.ArrayBuffer计算全量 hash —— 这仍会卡住主线程,哪怕用了 Fiber - 混淆 PHP 的
Fiber类(协程)与 React Fiber —— 二者命名巧合,技术模型完全不同
如何在 Fiber 环境中安全做分片上传
核心思路:把耗时操作移出主线程,再用 Fiber 的调度能力保障 UI 响应性。关键不是“用 Fiber”,而是“不让 Fiber 被拖垮”。
- 分片切分用
file.slice()—— 它是浏览器原生 API,轻量且无阻塞,但别一次性切完几十 GB(内存爆掉) - 哈希计算必须用 Web Worker:把
SparkMD5或SubtleCrypto.digest()移入 worker,通过postMessage传回 chunk hash 和 file hash - 上传请求用
fetch+AbortController,每个切片独立控制;避免Promise.all集体失败,改用for await...of或队列重试 - 进度更新走
useState+useTransition:对非紧急状态(如“已上传 12/287 片”)用startTransition包裹,防止高频率 setState 触发重排
常见错误:把切片逻辑写在 render 函数里
比如在组件顶层直接调用 file.slice() 或循环生成 chunks 数组 —— 这会导致每次 re-render 都重新切片,浪费 CPU 且可能产生不一致的 chunk 引用。
- 正确做法:用
useMemo缓存切片结果,依赖项仅含file和chunkSize - 更稳妥:切片动作放在用户点击“开始上传”后,用
useCallback封装,配合useState存储chunks列表 - 危险信号:Chrome DevTools Performance 面板中看到长任务(>50ms)集中在 JS 执行,且堆栈含
slice或arrayBuffer—— 说明没做 worker 卸载
真正起作用的 Fiber 相关配置点
这些不是“实现上传”,而是让上传过程对用户更友好:
-
startTransition包裹上传触发逻辑:防止按钮点击后界面冻结,“正在准备切片…” 状态能立即响应 -
useDeferredValue用于展示“剩余时间预估”这类非关键派生状态,避免因频繁更新拖慢主流程 - 服务端返回合并失败时,用
useOptimistic回滚 UI 到“上传完成但未合并”态,而不是闪退到初始页 - 不要在
render中调用XMLHttpRequest.upload.onprogress—— 应该用useEffect初始化监听器,并确保 cleanup 正确释放引用
最易被忽略的一点:分片上传的可靠性不取决于前端用了什么框架,而取决于服务端是否支持幂等上传、断点续传和原子合并。Fiber 再强,也救不了一个没校验 Content-MD5 头、不记录 upload_id 状态的服务端接口。











