JavaScript如何同时调用FileReader两个读取方法并移除多余循环
核心结论
- 无法直接链式调用
readAsArrayBuffer()与readAsDataURL():FileReader实例同一时间仅能执行一个读取任务,连续调用两个读取方法会直接中断前一个任务;且所有read类方法都是异步无返回值的,原生不支持链式调用。 - 无需两次遍历文件列表,完全可以在单次遍历流程中完成MIME校验、DataURL读取两个操作,减少冗余循环和多余的实例创建开销。
原有代码问题说明
你当前的两轮循环实现除了冗余遍历外,还存在几个潜在bug:
- 循环变量
i未做块级作用域声明,会出现异步回调执行时i值已经遍历到末尾的索引错乱问题 images数组没有提前初始化对应索引的项,第一次onload回调赋值is_valid时会访问到undefined- 第二个循环内错把
images写为image,会直接触发引用错误
优化后实现
只需要单次遍历文件列表,在ArrayBuffer读取完成、做完MIME校验后,紧接着触发同个文件的DataURL读取即可,参考代码如下:
const images = []; const fileList = dt.files; for (let i = 0; i < fileList.length; i++) { const currentFile = fileList[i]; // 提前初始化数组对应项,避免后续访问undefined images[i] = { file: currentFile, is_valid: false }; // 第一步:读取ArrayBuffer做MIME校验 const bufferReader = new FileReader(); bufferReader.fileIndex = i; bufferReader.onload = function (e) { const arrayBuffer = e.target.result; // 替换为你实际的MIME类型检测逻辑 images[this.fileIndex].is_valid = checkMimeTypeByBuffer(arrayBuffer); // 校验完成后直接读取DataURL,不需要新开循环 const dataUrlReader = new FileReader(); dataUrlReader.fileIndex = this.fileIndex; dataUrlReader.onload = function (loadEvent) { const imgItem = images[this.fileIndex]; const dataUrl = loadEvent.target.result; if (imgItem.is_valid) { // 合法图片的加载逻辑,比如给img标签赋值src、预览等 } else { // 非法文件的提示、过滤逻辑 } }; dataUrlReader.readAsDataURL(currentFile); }; // 仅需校验MIME的话可以只读取文件前几个字节,大幅提升大文件处理性能 bufferReader.readAsArrayBuffer(currentFile.slice(0, 16)); }
优化提示:绝大多数文件的MIME类型标识都存在于文件头前16字节内,不需要把整个文件读入ArrayBuffer做校验,调用
file.slice()截取文件头部片段读取即可,大文件场景下内存开销能降低99%以上。
内容的提问来源于stack exchange,提问作者Carlo Jimenez
相关产品推荐
相关产品推荐

