FileReader onloadend 中循环变量的值

value of loop variable in FileReader onloadend

我正在尝试处理通过 html5 dropzone/fileinput 创建的文件列表。 files[] 实际上不是一个 FileList,而是一个包含 File 对象的数组。

只要 files[] 仅包含 1-2 个文件,此方法就有效,但突然有更多文件时,每个控制台输出都是相同的(files[] 中的最后一个文件)。例如,对于 4 个文件,我得到 4 次 "filereader.onloaded: File: save-view.html index:4",其中 save-view.html 是最后一个文件。

    for(var i=0; i < files.length; i++)
    {
        var filereader = new FileReader();
        filereader.myfile = files[i];
        filereader.myindex = i;

        filereader.onloadend = function()
        {
            console.log("filereader.onloaded: File: "+filereader.myfile.name+" index:" +filereader.myindex);
            //here we call some other functions which most likely don't cause any problems
        }
        filereader.readAsArrayBuffer(file);
    }

我已经尝试了很多,比如创建一个 filereader 数组(这样 var filereader 永远不会被覆盖),并将索引保​​存为 filereader 的附加成员变量(这样值在 i++ 之后不会丢失),但是 none 有效。

filereader 随着循环的每次迭代而变化,并且循环不会在每次继续之前等待回调触发。因此,每当触发 onload 回调时,filereader 可能没有与特定 onload 事件关联的 FileReader 对象。

要确保您在回调中使用正确的 FileReader 对象,请使用 this 关键字,或者您可以从传递给回调的事件对象中获取它;

filereader.onloadend = function(event)
{
    console.log("filereader.onloaded: File: "+this.myfile.name+" index:" +event.target.myindex);
    //here we call some other functions which most likely don't cause any problems
}

你需要适当的关闭。在 Javascript 中,变量的范围不取决于花括号,而是取决于它们所在的函数。所以即使你的变量是在 for 循环中定义的,它实际上也可以在它之外使用,并且它是整个循环中唯一一个相同的变量。

您可以通过添加适当的闭包来解决此问题:

for(var i=0; i < files.length; i++)
{
    (function(f, i)
    {
        var filereader = new FileReader();
        filereader.onloadend = function()
        {
            console.log("filereader.onloaded: File: "+f.name+" index:" +i);
            //here we call some other functions which most likely don't cause any problems
        }
        filereader.readAsArrayBuffer(file);
    })(files[i], i);
}

请注意,for 循环中定义的 i 现在是与匿名函数参数列表中定义的 i 不同的变量。通过将变量传递给函数,它们将被复制到新变量中,这些变量将在整个脚本中保持独立。此外,现在会为 for 循环的每次迭代创建一个新的 filereader 变量。