Javascript 在对象内部使用FileReader

Javascript 在对象内部使用FileReader,javascript,filereader,Javascript,Filereader,我有一个对象,它有一个解析wav文件的loadFile()方法。我一直在对象外部使用FileReader,并将loadFile()从读取的文件中传递ArrayBuffer,让它从那里接管。我希望可能有许多对象,因此我希望在loadFile()方法中封装一个FileReader,这样我就不必为每个对象处理外部的所有读卡器代码。问题是,我不确定这将如何运作。下面是一个可视代码: function MyObject() { this.property; this.anotherProp

我有一个对象,它有一个解析wav文件的
loadFile()
方法。我一直在对象外部使用
FileReader
,并将
loadFile()
从读取的文件中传递
ArrayBuffer
,让它从那里接管。我希望可能有许多对象,因此我希望在
loadFile()
方法中封装一个
FileReader
,这样我就不必为每个对象处理外部的所有读卡器代码。问题是,我不确定这将如何运作。下面是一个可视代码:

function MyObject() {
    this.property;
    this.anotherProp;
    this.data = new Array(); // array to be filled with PCM data for processing
}

// pass a File object
MyObject.prototype.loadFile = function(file) {
    var reader = new FileReader();
    reader.readAsArrayBuffer(file);

    reader.onload = function(event) {

        var buffer = event.target.result;

        // do lots of stuff with buffer and eventually fill up this.data[]

    }

}

MyObject.prototype.doProcessing = function() {

    // process this.data[]

}

var file; // a File object I grabbed from somewhere

var myObj = new MyObject();

myObj.loadFile(file);

myObj.doProcessing();
loadFile()
在这里会发生什么?在我在
myObj.data[]中有任何数据之前,
loadFile
会返回吗?或者它会在返回之前等待
reader.onload
启动吗?如果这样做是错误的,我应该怎么做?同样,如果
loadFile()
中的
reader.onload
失败,我希望
loadFile()返回
false
该怎么办

可能的解决方案:


当前解决方案:我最终将文件解析功能从对象移到了web worker中,并发现了
FileReaderSync
。现在,我将文件发送给web worker,并在返回结果后创建一个对象。

Javascript中的事件是异步的,因此您必须假设
loadFile
将在
onload
运行之前返回(总是假设在最坏的情况下,因为您无法预测异步调用何时完成)

您通常的选择是在
loadFile
中添加一个回调参数,一旦
onload
完成,您将调用该参数,或者如果您希望这样做,可以选择集成延迟/未来


还有一个提示:在分配
onload
处理程序后,需要调用
readAsArrayBuffer
,因为它是异步的,如果您首先指示浏览器读取文件,然后将事件附加到该文件上,则始终有可能错过此事件。

是,loadfile将在文件实际加载之前返回。 一个好的方法可能包括使用承诺

例如,您可以使用Q库。 以下是API的链接:

如果您已经使用jQuery,那么$.Deferred对象就足够了,尽管我建议您使用Q库提供的承诺

MyObject构造函数可以定义一个延迟的(最好是私有的)函数,由
reader.onload
函数解析

对MyObjor实例的实际使用知之甚少,请将下面的内容视为伪代码。

function MyObject() {
    this.def = $.Deferred(); //the deferred to be resolved when the content has been loaded
    this.property;
    this.anotherProp;
    this.data = new Array(); // array to be filled with PCM data for processing
}

// pass a File object
MyObject.prototype.loadFile = function(file) {
    var obj = this,
        reader = new FileReader();
    this.def = $.Deferred();
    reader.readAsArrayBuffer(file);

    reader.onload = function(event) {
        var buffer = event.target.result;
        obj.def.resolve();
        // do lots of stuff with buffer and eventually fill up this.data[]
    }

}

MyObject.prototype.doProcessing = function() {
    this.def.done(function(){
        // process this.data[]
        console.log('resolved');
    });
}

var file; // a File object I grabbed from somewhere
var x = new MyObject();
x.loadFile(file);
x.doProcessing(); //this would print 'resolved' when the file is loaded 

添加'var self=this;'在reader onload()函数上方,在onload()中使用self.data=buffer,然后在reader.onload()的末尾调用self.doProcessing(),您真是棒极了……谢谢,这部分地让我找到了我当前的解决方案。我试着在我的对象中添加一个onload方法,该方法似乎正在工作:是的,Robby,这是一个很好的面向事件的工作解决方案。在这种情况下,解决方案是合理且易于理解的。如果期望的行为变得过于复杂,我建议你考虑使用承诺,因为它们是一个强有力的事件抽象。令人敬畏的,我肯定会检查出承诺,如果事情变得复杂如你所说。我感谢你的意见!只是一个机警的乔瓦尼,这是对承诺的一种不好的使用。实际上,您希望返回loadFile函数的承诺,并在外部处理返回值的操作,最终得到以下用例:
x.loadFile(file)。然后(x.doProcessing)
。否则,这个代码示例并不比使用回调更好,实际上更复杂。它似乎起作用了。如果您看到它的潜在问题,请告诉我:通常您会将回调函数作为参数传递,而不是硬编码它们以增加灵活性。例如,fiddle的这个修改版本:或者使用jQuery对承诺的定义——处理错误状态在这两个方面都非常简单,带有承诺的解决方案是一行,然后您需要将自己附加到承诺上的
.fail
接口。