在调用类方法之前,请确保在类构造函数中完成异步代码

时间:2019-06-30 20:34:00

标签: javascript asynchronous callback xmlhttprequest es6-class

我正在尝试创建一个将文件名传递给构造函数的类,使用XmlHttpRequest加载文件,并将结果存储在类变量中。问题在于request.onreadystatechange是一个异步函数,因此方法getData在构造函数完成之前最终被调用。因此,数据的结果是不确定的。如何确保此类的方法在运行之前等待文件加载。我对异步代码和承诺并不陌生,所以请像我5岁时解释一下。

如我的代码所示,在超时中包装该方法可以解决该问题,但这是一个糟糕的解决方案,由于明显的性能问题,request.open的同步版本已过时,因此不幸地,这也不是解决方案。

test.html

<html>
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
        <script src="test.js"></script>
        <script>
            let test = new testClass('test.json')
            console.log(test.getData)
        </script>
    </body>
</html>

test.js

class testClass {
    constructor(filename) {
        this.loaded_data = undefined

        let request = new XMLHttpRequest()

        request.overrideMimeType('application/json')
        request.open('GET', filename)
        request.onreadystatechange = () => {
            if (request.status == '200' && request.readyState == 4) {
                /* Load and parse JSON here */
                this.loaded_data = 'foo'
            }
        }

        request.send()
    }

    get getData() {
        setTimeout(() => {
            console.log(this.loaded_data)
        }, 500);

        return this.loaded_data
    }
}

1 个答案:

答案 0 :(得分:1)

从设计角度来看,文件本身不是“异步的”,异步加载该文件是什么。因此,您的类应该只代表一个已经加载的文件:

  class File {
    constructor(content) { this.content = content; }

现在加载该文件应该是静态的异步方法:

   static load(path) {
      return fetch(path) /*¹*/
         .then(res => res.json())
         .then(content => new File(content));
   }
 }

然后可以用作:

 (async function() {
   let file = await File.load('test.json')
   console.log(file.content);
 })()

¹:fetch()比XmlHttpRequest更易于使用,因为它返回Promise(因此可以很好地与async / await一起使用),并且提供了一些实用程序来解析/工作回应。在这种情况下,响应被解析为JSON。