【问题标题】:Loading a text file into a string, asyncronously, with pure javascript使用纯javascript将文本文件异步加载到字符串中
【发布时间】:2018-10-09 17:37:39
【问题描述】:

在没有任何外部库的情况下,我无法将文本文件加载到前端 javascript 应用程序中的字符串中。

xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", filename, true)
xmlhttp.send()

xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == 4)
        myvariable = xmlhttp.responseText
}

此代码将文本文件异步加载到变量中,但该变量仅在最终返回响应时在 onreadystatechange 块内可用。 任何在此范围之外获取此变量的尝试都会导致代码在返回响应之前执行,并且该变量始终未定义。

function getFile(filename, callback) {

    xmlhttp = new XMLHttpRequest();
    xmlhttp.open("GET", filename, true)
    xmlhttp.send()

    xmlhttp.onreadystatechange = function() {
         if (xmlhttp.readyState == 4)
            callback(xmlhttp.responseText)
    }
 }

function loadFile(filename) {
    var myString
    getFile(filename, function(reponseText){
        myString = responseText
    })
    return myString
}

有些人提出了这种模式作为问题的解决方案。然而,这提出了完全相同的问题,在提出这个问题的大多数场景中,真正解决问题的是

async: false

我正在尝试抽象出文件加载过程,因为它会在我的代码中发生多次,并且可能会被修改多次。我希望将整个文件加载抽象为一个函数,我可以在代码中的任何位置调用它,而不必担心将我的代码嵌套在算法上不重要的 IO 任务的回调中。我也试图避免只使用同步请求。但是在阅读了其他解决方案后,我不确定这是否可行。

我正在尝试在没有任何外部库的纯 javascript 中执行此操作。

编辑 1/5/18

尝试使用 async/await 和 Promises 实现这一点后,我遇到了非常相似的情况。

function getFile(filename) {
    return new Promise(function(resolve, reject){   

        xmlhttp = new XMLHttpRequest()
        xmlhttp.open("GET", filename, true)
        xmlhttp.overrideMimeType("text/plain")
        xmlhttp.send()

        xmlhttp.onload = function() {
            if (xmlhttp.status == 200) {
                resolve(xmlhttp.responseText)
            }
            else {
                reject()
            }
        }
    })
}

async function loadFile(filename) {
    myfile = await getFile(filename)
    return myfile
}

调用 loadFile() 函数会返回一个解析为 myfile 值的 Promise。但是要获得该值,我们需要调用

loadFile().then(myfile => { /* Use my varible here */})

这让我处于完全相同的情况,我的其余代码需要包装在由不重要的 IO 调用创建的函数中。奇怪的是,在声明为 async 的 loadFile() 函数内部,如果我使用 await 关键字,代码的行为是同步的,这是我试图在我的其余代码中获得的行为。

async function loadFile(filename) {
    myfile = await getFile(filename)
    /* myfile is set here, like in syncronous code*/
    return myfile
    /* This returns a promise, getting us back to square 1*/
}

async/await 语法似乎没有比直接使用 Promise 提供任何优势,无论如何我不得不手动构造一个 Promise,而且我似乎正在将结果值直接解包并重新打包到另一个 Promise 中。

我错过了什么吗?

【问题讨论】:

  • 摆脱loadFile() 并始终调用getFile()。或者更强大的现代方法而不是回调是使用承诺。见How do I return the response from an asynchronous call
  • JavaScript 和浏览器 API 的基本异步特性几乎无法避免。
  • 在这种情况下,像 superagent 或 axios 这样的小型请求库将为您节省大量的开发时间。如果您不需要支持旧版浏览器,也可以考虑使用更新的 fetch() API
  • 如果您认为可能,请查看 await*/*async 和/或 Promise。否则,回调机制是一种常见的解决方案,因为文件加载器是异步的,我认为您无法编写(干净)异步工作的同步代码。
  • 看过 await/async 和 Promises 后,似乎异步函数总是返回另一个 Promise(即使它没有返回值?)。 “等待”来自异步函数的承诺的结果提供了该函数内部已解决的承诺的值,但不可能直接从异步函数返回该值?

标签: javascript ajax promise async-await xmlhttprequest


【解决方案1】:

您可以将对象传递给 loadFile 函数并捕获 fileResponse,如下所示:

    var fileObject = {
      fileResp: ''
    }

    function loadFile(filename, fileObject) {
        getFile(filename, function(reponseText){
            fileObject.fileResp = responseText
            triggerFileComplete()
        })
        return fileObject;
    }

   function triggerFileComplete() {
    // Do your next operation
    }

也许稍后或在 triggerFileComplete 中,您可以使用 fileObject.fileResp。

【讨论】:

    猜你喜欢
    • 2018-10-17
    • 2015-04-05
    • 2019-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多