2016-08-04 140 views
2

我是JavaScript新手。我找到了一个使用javascript在StackOverflow上打开本地文件的示例。在Google搜索之后,我可以将我的Chrome设置为允许读取本地文件,然后我就可以运行该示例。但是,我想返回字符串allText,稍后在我的脚本中使用它。但字符串在readTextFile()之外变成undefined在JavaScript中打开本地文件

还有一个类似的问题here。这似乎与AJAX的异步功能有关。我现在几乎无法理解这些行话。我只是不明白为什么在这篇文章中XMLHttpRequest.open()的第三个参数设置为true

无论如何,下面是我目前的代码。我想使用allText外部函数readTextFile()

<!DOCTYPE html> 
<html> 
    <script> 
     function readTextFile(file) 
     { 
      var allText; 
      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; 
         alert(allText); 
        } 
       } 
      } 
      rawFile.send(null); 
      return allText; // this is the part that goes wrong I think 
     } 

     t = readTextFile("foo.file"); 
     document.write(t) // print out "undeifned" instead of the correct answer 

    </script> 
</html> 
+0

可能的重复[如何返回来自异步调用的响应?](http://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-调用) – Marty

+2

你声明'allText'两次(使两个变量具有相同的名称但不同的范围),删除变量之前的第二个'var'关键字。祝你好运! –

+0

@SantiagoHernández这是它的一部分,但它仍然不能解决异步履行竞争条件,并且在XHR请求完成之前它仍然是未定义的。 –

回答

3

这实际上很可能是范围问题。因为您正在异步设置所有文本,所以在函数返回后不可立即使用。另外,你正在重新初始化一个函数中的所有文本,这与返回的范围无关。

rawFile.onreadystatechange在函数返回后执行。您可以将执行过程移至XHR回调函数中,也可以将函数包装在承诺中,这仍然需要您修改控制流程。

移动document.write

<!DOCTYPE html> 
<html> 
    <script> 
     function readTextFile(file) 
     { 
      var allText; 
      var rawFile = new XMLHttpRequest(); 
      rawFile.open("GET", file); 
      rawFile.onreadystatechange = function() 
      { 
       if(rawFile.readyState === 4) 
       { 
        if(rawFile.status === 200 || rawFile.status == 0) 
        { 
         allText = rawFile.responseText; 
         document.write(allText); 
        } 
       } 
      } 
      rawFile.send(null); 
     } 

     readTextFile("foo.file"); 

    </script> 
</html> 

Promisified:

function readTextFile(file) { 
    return new Promise(function (fulfill, reject) { 

    var allText; 
    var rawFile = new XMLHttpRequest(); 
    rawFile.open("GET", file); 
    rawFile.onreadystatechange = function() { 
     if (rawFile.readyState === 4) { 
     if (rawFile.status === 200 || rawFile.status == 0) { 
      fulfill(rawFile.responseText) 
     } 
     } 
    } 
    rawFile.send(null); 
    }); 
} 
readTextFile("foo.file") 
    .then(function (t) { 
    document.write(t); 
    }); 

这两项将确保您的脚本不尝试使用allText直到它被XHR返回请求。

尽管Santiago Hernández指出,XHR请求是同步的,范围问题与我第一次假设的性质不同。问题在于重新声明函数中的变量,导致返回的变量未定义。

+2

实际上'allText'正在同步设置,阻塞主线程......并且它在'rawFile.onreadystatechange'完成后完全可访问 –

+1

是!我的错。最初,我没有注意到XHR请求上的异步“false”标志。信贷在哪里到期,你有正确的答案:) –

+2

没问题:) ..顺便说一句,回调地狱是真正的地狱 –