文件过多时 input.files 读取会卡顿甚至崩溃,因 FileList 初始化开销大;建议先校验数量、分批处理、用 DocumentFragment 批量插入;iOS Safari 不支持 multiple,需 UA 检测并降级为多个单文件输入。

文件过多时 input.files 读取卡顿甚至崩溃
选中 100+ 个文件后,Array.from(input.files) 或遍历 input.files 会明显卡 UI,极端情况直接触发浏览器“页面无响应”提示。这不是 JS 写得慢,而是 FileList 对象在底层需为每个文件建立引用,数量越大,初始化开销越高。
实操建议:
立即学习“前端免费学习笔记(深入)”;
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
- 不要一上来就
Array.from(input.files)—— 先用input.files.length快速判断是否超限(比如 > 20),超了就立刻alert("最多支持 20 个文件,请重新选择")并input.value = "" - 真要处理大量文件,分批读取:用
for (let i = 0; i 限制首轮预览/校验数量 - 避免对每个文件都调用
file.text()或FileReader.readAsDataURL()—— 这俩操作是同步阻塞的,100 个文件全读会锁死主线程 - 改用
URL.createObjectURL(file)快速生成预览 URL,仅对用户点击展开的文件再读内容
拖拽多文件时 event.dataTransfer.files 性能比 input.files 更差
拖入 50+ 文件到 drop 区域,event.dataTransfer.files 的访问延迟比 input.files 更高,且部分浏览器(尤其是旧版 Edge)在此场景下会丢文件或报 SecurityError。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 拖拽入口必须加
preventDefault(),否则 Chrome/Firefox 会直接打开文件而非触发 drop - 拿到
event.dataTransfer.files后,立刻用Array.from(files).slice(0, 30)截断,别等后续逻辑再处理 - 拖拽和点击两种路径应共用同一套校验逻辑,但初始化阶段就做长度拦截,别让大数组进入主流程
- 移动端不支持拖拽,所以该路径纯属桌面端优化,iOS/Android 用户走
<input type="file" multiple>即可
UI 提示必须实时、轻量、不依赖 DOM 重排
显示“已选 47/50 个文件”这类提示时,如果每次 change 都用 innerHTML 重写整个提示区域,配合动画或 CSS 过渡,在高频选择(比如反复删增)下会明显掉帧。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 只更新数字部分:
countEl.textContent = `${files.length}/50`,避免触发 layout - 禁用上传按钮用
uploadBtn.disabled = files.length === 0 || files.length > 50,别加 class 切换 - 文件列表展示用
document.createDocumentFragment()批量插入,而不是循环appendChild - 别在 change 回调里调用
console.log(files)—— FileList 的 console 展开是惰性加载,点开才触发,但开发者常误以为它“只是打印”,实际会拖慢响应
移动端 iOS Safari 的 multiple 表现与降级策略
iOS Safari(包括所有 WebKit 内核 iOS 浏览器)对 multiple 的支持是“伪多选”:用户点选后,系统弹窗仍是单文件选择器,input.files.length 永远是 1,且不会报错,静默失效。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 用
navigator.userAgent.includes("iPhone") || navigator.userAgent.includes("iPad")检测 iOS,直接隐藏<input type="file" multiple>,换成多个单文件 input 或“点击添加”按钮 - 别依赖
input.multiple属性检测是否支持——它永远返回true,iOS 上属性存在但功能不生效 - 真正可靠的检测方式是监听 change 后检查
input.files.length > 1,若连续两次都 ≤ 1,可判定当前环境不支持原生 multiple - 即使做了降级,服务端仍要按多文件逻辑接收,因为安卓和桌面端正常走
files[],iOS 传来的单个文件也得兼容


















