带有结果和参数的 FileReader onload
Posted
技术标签:
【中文标题】带有结果和参数的 FileReader onload【英文标题】:FileReader onload with result and parameter 【发布时间】:2015-01-31 00:19:16 【问题描述】:我无法同时获得文件读取器的结果和 onload 函数中的一些参数。这是我的代码:
控件的html:
<input type="file" id="files_input" multiple/>
javascript 函数:
function openFiles(evt)
var files = evt.target.files;
for (var i = 0; i < files.length; i++)
var file=files[i];
reader = new FileReader();
reader.onload = function()
var data = $.csv.toArrays(this.result,separator:'\t');
;
reader.readAsText(file);
添加事件:
files_input.addEventListener("change", openFiles, false);
我在onload
函数中使用filereader.result
。如果我为此函数使用参数(如文件),我将无法再访问结果。例如,我想在 onload 函数中使用file.name
。如何解决这个问题?
【问题讨论】:
它是否适用于一个文件?尝试创建不同的阅读器,添加“var reader = new FileReader();” 使用一个简单的规则:在闭包的开头声明所有的局部变量。不要在for
、in
和其他类似语句中声明它们,因为这些语句不会创建闭包,因此声明的变量不是语句的本地变量。这将帮助您确定何时需要创建额外的闭包。
【参考方案1】:
使用
var that = this;
在函数范围内访问外部变量。
function()
that.externalVariable //now accessible using that.___
我的场景 - 使用 Angular 9。
我为此苦苦挣扎了很长时间,我似乎无法让它发挥作用。
我发现以下是访问function()
块内的外部变量的一个非常优雅的解决方案。
public _importRawData : any[];
importFile(file)
var reader = new FileReader();
reader.readAsArrayBuffer(file);
var data;
var that = this; //the important bit
reader.onloadend = await function()
//read data
that._importRawData = data; //external variables are now available in the function
上述代码中的一个重要部分是var
关键字,它将变量范围限定在功能块之外。
但是,当我在函数块之后访问data
的值时,它仍然未定义为在其他代码之后执行的函数。我尝试了异步和等待,但无法让它工作。而且我无法在这个函数之外访问data
。
可取之处是var that = this
行。
使用它允许在函数内部访问外部变量。所以我可以在函数范围内设置该变量,而不必担心代码何时执行。一经阅读,即可使用。
对于原始问题,代码为:
function openFiles(evt)
var files = evt.target.files;
for (var i = 0; i < files.length; i++)
var file=files[i];
var that = this; //the magic happens
reader = new FileReader();
reader.onload = function()
var data = $.csv.toArrays(this.result,separator:'\t');
that.file.name //or whatever you want to access.
;
reader.readAsText(file);
【讨论】:
【参考方案2】:对于打字稿;
for (var i = 0; i < files.length; i++)
var file = files[i];
var reader = new FileReader();
reader.onload = ((file: any) =>
return (e: Event) =>
//use "e" or "file"
)(file);
reader.readAsText(file);
【讨论】:
【参考方案3】:尝试将您的 onload 函数包装在另一个函数中。在这里,闭包让您可以通过变量 f
依次访问正在处理的每个文件:
function openFiles(evt)
var files = evt.target.files;
for (var i = 0, len = files.length; i < len; i++)
var file = files[i];
var reader = new FileReader();
reader.onload = (function(f)
return function(e)
// Here you can use `e.target.result` or `this.result`
// and `f.name`.
;
)(file);
reader.readAsText(file);
有关为何需要在此处关闭的讨论,请参阅以下相关问题:
JavaScript closure inside loops – simple practical example Javascript infamous Loop issue?【讨论】:
如果浏览器有FileReader
,我认为它支持forEach和bind :) 我认为最好使用bind来添加文件到onload回调
@Pinal 这是个好建议。我不会更新我的答案以包含这些,因为我想让我的答案尽可能接近 OP 提供的代码,并且只更改必要的内容(引入闭包),但最好了解这些功能。
类似的徒劳无功,在生产代码中,我很想将 FileReader 代码移动到它自己的从循环调用的命名函数中。闭包会按预期运行,它有助于分解代码。也就是说,给出的示例更适合演示技术解决方案。
如果可以的话,我会为这个答案投票 1000 次。谢谢!
谢谢伙计!帮了我很多!【参考方案4】:
事件处理是异步的,因此它们会获取所有封闭局部变量的最新值(即闭包)。要将特定的局部变量绑定到事件,您需要按照上面用户建议的代码进行操作,或者您可以查看以下工作示例:-
http://jsfiddle.net/sahilbatla/hjk3u2ee/
function openFiles(evt)
var files = evt.target.files;
for (var i = 0; i < files.length; i++)
var file=files[i];
reader = new FileReader();
reader.onload = (function(file)
return function()
console.log(file)
)(file);
reader.readAsText(file);
#Using jQuery document ready
$(function()
files_input.addEventListener("change", openFiles, false);
);
【讨论】:
这不太对。您应该为reader.onload
分配一个函数。您正在调用的 IIFE 不返回任何内容,因此一旦阅读器触发其加载事件,就不会运行任何代码。
我不明白为什么返回一个函数很重要,当这段代码只在 onload 事件上运行并且文件绑定到它时
目前,您的函数 (function(file)console.log(file))(file);
为您的 for
循环的每次迭代运行一次。它不返回任何东西,所以 reader.onload = undefined
用于循环的每个交互。因此,虽然您的console.log
确实打印了正确的文件名,但当reader
触发它的load
事件时,什么都不会运行。
感谢您强调,这是我的错,我应该解决这个问题【参考方案5】:
由于变量 file 在范围内,您可以使用 file 变量而不将其传递给函数。
function openFiles(evt)
var files = evt.target.files;
for (var i = 0; i < files.length; i++)
var file=files[i];
reader = new FileReader();
reader.onload = function()
alert(file.name);
alert(this.result);
;
reader.readAsText(file);
files_input.addEventListener("change", openFiles, false);
<input type="file" id="files_input" multiple/>
【讨论】:
谢谢,明白了:) 但是当我通过显示每个文件名和内容进行测试时,这似乎有效。运行上面的代码片段。我想我错过了一些会看到的东西。 上述代码在这种情况下有效,因为 onload 事件作为迭代的一部分发生(reader.readAsText)。而在***.com/questions/1451009 onclick 事件在迭代完成后发生 虽然这似乎可行,但当您运行上述 sn-p 并选择多个文件时,列表中的最后一个文件会显示多次。所以这不能按预期工作。【参考方案6】:您应该在“onload”处理程序中使用闭包。 示例:http://jsfiddle.net/2bjt7Lon/
reader.onload = (function (file) // here we save variable 'file' in closure
return function (e) // return handler function for 'onload' event
var data = this.result; // do some thing with data
)(file);
【讨论】:
以上是关于带有结果和参数的 FileReader onload的主要内容,如果未能解决你的问题,请参考以下文章
Java的 FileWriter类 和 FileReader类
3分钟上手JS中的FileReader对象(实现上传图片预览)