使用XMLHttpRequest获取两文件计算数值返回NaN的问题排查
嘿,咱们来看看你代码里的问题,其实主要是异步请求的时机没处理对,还有个小笔误,我给你拆解一下:
首先,你代码里有个明显的小错误:FTEXT2 = (FILE1.responseText); 这里应该是FILE2.responseText,不过这不是导致NaN的核心原因。
真正的问题是:XMLHttpRequest默认是异步的(第三个参数true),当你调用send()之后,浏览器会在后台发起请求,而代码会立刻继续执行后面的逻辑——这时候请求还没完成,responseText是空字符串!你用空字符串split出来的数组,split1[2]和split2[3]都是空值,转成数字就是NaN,相加自然也是NaN了。
接下来给你几种解决方案,从基础到更现代的写法:
方案1:用onload回调处理异步结果
把处理逻辑放在每个请求的onload事件里,确保只有当请求成功完成后才去读取responseText:
function testFiles(){ // 先处理第一个文件的请求 var FILE1 = new XMLHttpRequest(); FILE1.open("GET", 'filetest1.txt', true); // 请求完成后触发onload FILE1.onload = function() { // 先检查请求是否成功(状态码200) if (FILE1.status === 200) { const FTEXT1 = FILE1.responseText; // 第一个文件获取成功后,再请求第二个文件 var FILE2 = new XMLHttpRequest(); FILE2.open("GET", 'filetest2.txt', true); FILE2.onload = function() { if (FILE2.status === 200) { const FTEXT2 = FILE2.responseText; // 拆分每行,同时转成数字(还要trim掉换行/空格) const split1 = FTEXT1.split('\n').map(line => parseInt(line.trim(), 10)); const split2 = FTEXT2.split('\n').map(line => parseInt(line.trim(), 10)); // 这里是数字相加,不是字符串拼接 const output = split1[2] + split2[3]; console.log(output); // 应该输出7了 } else { console.error('获取filetest2.txt失败,状态码:', FILE2.status); } }; // 处理第二个请求的错误 FILE2.onerror = function() { console.error('请求filetest2.txt时出错'); }; FILE2.send(); } else { console.error('获取filetest1.txt失败,状态码:', FILE1.status); } }; // 处理第一个请求的错误 FILE1.onerror = function() { console.error('请求filetest1.txt时出错'); }; FILE1.send(); }
方案2:用Promise+async/await(更现代、更清晰)
如果不想陷入嵌套的回调地狱,可以把XHR封装成Promise,然后用async/await来写同步风格的异步代码,还能同时发起两个请求,效率更高:
// 封装一个通用的文件获取函数,返回Promise function fetchFile(url) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.onload = () => { if (xhr.status === 200) { resolve(xhr.responseText); } else { reject(new Error(`获取文件失败:状态码 ${xhr.status}`)); } }; xhr.onerror = () => { reject(new Error(`请求 ${url} 时发生网络错误`)); }; xhr.send(); }); } // 用async/await处理异步逻辑 async function testFiles() { try { // 同时发起两个请求,等待两者都完成 const [text1, text2] = await Promise.all([ fetchFile('filetest1.txt'), fetchFile('filetest2.txt') ]); // 处理数据:拆分并转成数字 const lines1 = text1.split('\n').map(line => parseInt(line.trim(), 10)); const lines2 = text2.split('\n').map(line => parseInt(line.trim(), 10)); const result = lines1[2] + lines2[3]; console.log(result); // 7 } catch (err) { // 捕获任何请求或处理中的错误 console.error('出错了:', err.message); } }
额外注意点
- 一定要转成数字:如果直接用字符串相加,
"3"+"4"会得到"34",而不是7,所以用parseInt或者Number把每行转成数字很重要。 - 处理空行/空白:文件末尾可能有多余的换行,导致split出来的最后一个元素是空字符串,用
trim()可以避免这种情况。 - 错误处理:不要忽略请求失败的情况,比如文件不存在、网络断开,加上
onerror或者Promise的catch能让代码更健壮。
内容的提问来源于stack exchange,提问作者kquinn
相关产品推荐
相关产品推荐

