JS的FileReader对象Onload方法异步问题(求大佬解答)

JS的FileReader对象Onload方法异步问题(求大佬解答)
最新回答
你滋润了

2022-05-17 21:30:24

这个问题涉及到 JavaScript 中 FileReader 的异步特性以及变量作用域的理解。以下是详细解答:

核心问题分析
  1. 异步执行顺序reader.onload 是异步回调函数,它会在 reader.readAsBinaryString() 完成后触发。因此,代码的实际执行顺序是:

    同步执行 console.log("nws2=",nws) 和 console.log("tt=",tt)(此时 nws 仍为空数组 [],tt 仍为 "aa")。

    异步执行 onload 回调,此时才会修改 nws 和 tt。

  2. 变量作用域与闭包

    nws 和 tt 在 handleUploadFile 函数作用域内定义,onload 回调通过闭包访问它物扮们,因此回调内对它们的修改会反映到外部。

    但由于异步性,外部的 console.log 无法捕获回调内的修改。

代码执行流程详解handleUploadFile(file, fileList) { let reader = new FileReader(); let nws = []; // 初始化为空数组 let tt = "aa"; // 初始化为 "aa" // 异步回调:文件读取完成后执行 reader.onload = function (e) { const data = e.target.result; const workBook = xlsx.read(data, { type: "binary" }); // ...(处理 workBook 的代码) tt = "bb"; // 修改 tt 的值 console.log("nws1=", nws); // 此时 nws 已被填充数据 // ...(填充 nws 的循环) }; // 同步执行:此时 onload 尚未触发! console.log("nws2=", nws); // 输出 [](未修改) console.log("tt=", tt); // 输出 "aa"(未修改) reader.readAsBinaryString(file.raw); // 启动异步读取 this.excelData = nws; // 此时 nws 仍是 []!}关键问题解答
  1. 为什么 nws1 和 nws2 输出一致?

    nws2 在 onload 回调绑定前输出,此时 nws 未被修改。

    nws1 在 onload 回调执行后输出,已填充数据。

    但你的代码中可能未正确展示 nws1 的输出时机(例如,可能在另一个函数中调用)。实际应为:

    nws2:[](同步)

    nws1:[填充后的数据罩让灶](异步回调内)

  2. 为什么 tt 输出 "aa" 而不是 "bb"?

    console.log("tt=", tt) 在 onload 回调绑定前同步执行,此时 tt 未被修改。

    若你在 onload 回调外访问 tt,永远得到 "aa";回调内的修改仅在回调内生效。

如何修复?

若需在文件读取完成后操作数滑宏据,必须将逻辑放在 onload 回调内

handleUploadFile(file, fileList) { let reader = new FileReader(); reader.onload = (e) => { const data = e.target.result; const workBook = xlsx.read(data, { type: "binary" }); const wsname = workBook.SheetNames[0]; const ws = xlsx.utils.sheet_to_json(workBook.Sheets[wsname], { defval: "", range: 1 }); const nws = ws.map(item => ({ patrolPosition: item["x1"], patrolName: item["x2"], patrolCardId: item["x3"], patrolDetail: item["x4"], })); console.log("nws=", nws); // 正确输出数据 this.excelData = nws; // 正确赋值 }; reader.readAsBinaryString(file.raw);}总结
  • 异步回调的特性:onload 内的代码在文件读取完成后执行,而外部代码同步执行。
  • 变量作用域:回调通过闭包访问外部变量,但修改需在回调内确认。
  • 解决方案:将依赖异步结果的逻辑全部放入回调中,或使用 Promise/async/await 封装(推荐)。

通过理解异步执行顺序和作用域,可以避免此类问题。