[英]Synchronous XMLHttpRequest when reading file in JavaScript
我正在尝试在js中实现算法。 我想从文本文件(逐行)读取数据而无需选择输入 ,只需在源代码中设置文件路径即可。 我已经尝试了所有关于stackoverflow的方法,但它们对我都不起作用。
要读取的文件正好在我的本地主机上。
有人可以帮忙吗?
---------更新----------
这是我的代码,发生错误为:
不赞成在主线程上使用同步XMLHttpRequest,因为它会对最终用户的体验产生不利影响。
我尝试读取的文件恰好在我的localhost文件夹中。
<html>
<head>
</head>
<body>
<script type="text/javascript">
var rules = {};
var left, right1, right2, probability;
// read rule file and process it into rules format
function readTextFile(file) {
var rawFile = new XMLHttpRequest();
rawFile.open("GET", file, false);
rawFile.onreadystatechange = function () {
if(rawFile.readyState === 4) {
if(rawFile.status === 200 || rawFile.status == 0) {
var allText = rawFile.responseText;
allText = allText.split("\n");
allText = allText.splice(0, allText.length-1);
allText.forEach(function (rule) {
rule;
left = rule[0];
probability = parseFloat(rule.slice(rule.indexOf(":")+2));
rules[left] ? rules[left] : rules[left] = {}; // init left
if (rule[6] == " ") {
right1 = rule[5];
right2 = rule[7];
rules[left][right1] ? rules[left][right1] : rules[left][right1] = {}; // init right1
rules[left][right1][right2] = probability;
} else {
right1 = rule.slice(5, rule.indexOf(":") - 1);
rules[left][right1] = probability;
}
});
}
}
}
rawFile.send(null);
}
readTextFile("rules.txt");
console.log(rules);
</script>
</body>
</html>
---------------------更新2 --------------------------
规则如下:
A -> D C : 0.00688348825155337
A -> D M : 0.03345377673232689
A -> G F : 0.43257400994797
A -> L C : 0.4225829540437112
A -> L H : 0.014080236090023698
A -> L M : 0.06637630954705294
A -> N M : 0.001218212356843953
A -> O M : 0.022583482305501317
您得到的警告是因为通常不鼓励使用同步XMLHttpRequest:如果服务器没有立即响应,则它可能会挂起浏览器。
如果只打算在localhost
上运行此命令,则可以忽略警告,或者将同步请求更改为异步,或者更好。
使它成为同步的原因是.open()
调用的第三个参数:
rawFile.open("GET", file, false);
要使其异步,请将其更改为true:
rawFile.open("GET", file, true);
或者直接省略参数,因为默认为true
:
rawFile.open("GET", file);
您的其余代码应按原样工作。 (它在快速测试中对我有用。)您已经以一种可以处理异步请求的方式编写了代码:当readyState === 4
,您在onreadystatechange
回调中使用数据,而不是假设它发出.open()
调用后,它将立即可用,因为同步代码可能会这样做。
有关更多信息,请参见MDN文档 。
更新1
在onreadystatechange
回调之外未定义rules
的问题是正常的预期行为。 请记住,我们现在已将请求更改为异步 。 也就是说, .open()
调用会发起请求,然后立即返回,直到服务器(甚至localhost
上的服务器)返回数据。
解决方案很简单:发出请求后不要尝试内联访问数据。 相反,只能从成功回调函数内部或从该回调函数调用的另一个函数中访问它。
例如,在更新的代码中,只需将console.log()
调用移动到成功回调的末尾,如下所示,或者如果需要的话,从那里调用您自己的另一个函数。 无论您要对数据进行任何其他处理,请遵循相同的模式。
另外,不要在代码顶部声明rules
; 这只会导致混乱,因为在调用成功回调函数之前(如您所发现的), rules
的值不可用。 而是在回调中声明它。
同样, left
, right1
, right2
和probability
仅在forEach()
回调内部forEach()
,因此应在此处声明它们。
更新2
正如我们在评论中讨论的那样,正则表达式可能是进行这种字符串解析的好方法。
这是一个示例,它说明了原始代码的工作版本以及使用正则表达式解析规则的新版本。
我测试过的rules.txt
文件如下所示:
A -> D C : 0.00688
A -> G F : 0.43257
B -> with : 0.1875
C -> with : 0.2
JavaScript代码为:
function readRules( file ) {
var request = new XMLHttpRequest();
request.open( 'GET', file );
request.onreadystatechange = function() {
if( request.readyState === 4 ) {
if( request.status === 200 || request.status == 0 ) {
processRules1( request.responseText );
processRules2( request.responseText );
}
}
}
request.send( null );
}
function processRules1( allText ) {
var rules = {};
allText = allText.split("\n");
allText = allText.splice(0, allText.length-1);
allText.forEach(function (rule) {
left = rule[0];
probability = parseFloat(rule.slice(rule.indexOf(":")+2));
rules[left] ? rules[left] : rules[left] = {}; // init left
if (rule[6] == " ") {
right1 = rule[5];
right2 = rule[7];
rules[left][right1] ? rules[left][right1] : rules[left][right1] = {}; // init right1
rules[left][right1][right2] = probability;
} else {
right1 = rule.slice(5, rule.indexOf(":") - 1);
rules[left][right1] = probability;
}
});
console.log( JSON.stringify( rules, null, 4 ) );
}
function processRules2( rulesText ) {
var reRule = /^(\w) -> (\w+)( (\w))? : ([\d.]+)$/gm;
var rules = {};
rulesText.replace( reRule, function(
line, left, right1, dummy1, right2, probability
) {
if( ! rules[left] ) rules[left] = {};
if( right2 ) {
if( ! rules[left][right1] ) rules[left][right1] = {};
rules[left][right1][right2] = probability;
} else {
rules[left][right1] = probability;
}
});
console.log( JSON.stringify( rules, null, 4 ) );
}
readRules( 'rules.txt' );
processRules1()
使用原始技术,而processRules2()
使用正则表达式。
两种版本的test rules.txt
文件记录的结果相同:
{
"A": {
"D": {
"C": 0.00688
},
"G": {
"F": 0.43257
}
},
"B": {
"with": 0.1875
},
"C": {
"with": 0.2
}
}
正则表达式本身是processRules2()
函数的一部分,看上去有些令人生畏:
var reRule = /^(\w) -> (\w+)( (\w))? : ([\d.]+)$/gm;
除了在这里没有详细解释之外,让我将您引向regex101.com上的一个页面 , 该页面测试正则表达式并解释其工作方式。 如果他们的解释不清楚,请给我喊。
除了稍微短一点,正则表达式还使代码更加灵活。 例如,假设规则文件有时在值之间使用多个空格,而不是在现有文件中使用单个空格。 使用原始方法,您将不得不重新计算所有字符偏移量,并包括处理单个空格和多个空格的代码。 使用正则表达式,就像更改一个 (与单个空格匹配)到
+
(与一个或多个空格匹配)。
还要注意,正则表达式负责将规则文件分成几行,并忽略文件末尾的空行(而不是使用.splice()
删除最后一行)。 空行与正则表达式完全不匹配,因此会被忽略。
代码中的一件事是使用.replace()
方法。 通常,当您实际上要用其他东西替换字符串中的字符时,使用此方法。 但是在这里,我们只是使用它作为在字符串中的每个匹配项上调用函数的方法,然后我们忽略了.replace()
返回的值。
最后一个建议:在几个地方,原始代码是这样的:
rules[left] ? rules[left] : rules[left] = {};
在将结果实际分配给某些对象的类似用途中,条件运算符可能会很方便,但是在这种特殊情况下,使用普通的if
语句更简单明了:
if( ! rules[left] ) rules[left] = {};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.