2

我正在做类似于http://www.html5rocks.com/en/tutorials/file/dndfiles/

我正在做的是我一次读取一个选定文件的内容,以验证它们的行是否通过了一些正则表达式测试。完成验证所有文件后,我需要相应地更新(启用/禁用)一些按钮,因此回调功能

是否有可能有一个回调函数在读取所有内容后执行某些操作?

HTML:

<input type="file" id="files" name="files[]" multiple />

Javascipt:

<script>
  function handleFileSelect(evt) {
    var files = evt.target.files; // FileList object

    // files is a FileList of File objects. List some properties.
    var validArray = [];
    for (var i = 0, f; f = files[i]; i++) {
        //Create new file reader
        var r = new FileReader();
        //On load call
        r.onload = (function (f) {
            return function (e) {
                var contents = e.target.result;
                var lines = contents.split('\n');
                
                for(var i=0; i<lines.length; i++){
                    //Validate regex of line here
                    //If line does not pass, append file name to validArray and break  
                }
                                
            };
        })(f);
        r.readAsText(f);
    }
  }

  document.getElementById('files').addEventListener('change', handleFileSelect, false);
</script>
4

4 回答 4

5

来这里寻找类似的答案。我想在加载和处理所有文件后调用一个函数。@Snuffleupagus 提供的解决方案对我不起作用,因为在读取所有文件之后调用该函数,但在 onload 函数完成处理之前调用该函数。我找到了一个解决方案,如下所示(不确定它是否是“最干净的”,但它对我有用)。

var processedCount=0; // global variable
var totalFiles = 0; // global variable

function handleFileSelect(evt) {
  var files = evt.target.files; // FileList object

  totalFiles = files.length; // important

  // files is a FileList of File objects. List some properties.
  for (var i = 0, f; f = files[i]; i++) {
    //Create new file reader
    var r = new FileReader();
    //On load call
    r.onload = (function(theFile){
        return function(){
          onLoadHandler(this,theFile);
          onLoadEndHandler();
       };
    })(f);
    r.readAsText(f);
  }
}

function onLoadEndHandler(){
  processedCount++;
  if(processedCount == totalFiles){ 
    // do whatever - this code will run after everything has been loaded and processed
  }
}

我尝试使用 r.onloadend 但它被调用得太早了。我相信因为我的函数'onLoadHandler'需要几秒钟来处理每个文件,并且在文件加载完成但在'onload'中的代码完成运行之前调用onloadend。

于 2012-12-21T18:16:41.887 回答
2

绝对地。回调只是像任何其他普通参数一样传递,因此我们最终将添加另一个参数并将事件侦听器更改为使用额外参数handleFileSelect调用的匿名函数。handleFileSelect

我设置了一个小提琴来给你一个快速的工作演示。

function handleFileSelect(evt, cb) {
    var files = evt.target.files; // FileList object

    // files is a FileList of File objects. List some properties.
    var output = [];
    for (var i = 0, f; f = files[i]; i++) {
      output.push('<li><strong>'+ escape(f.name) + '</strong>');
    }
    document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
    if(cb) cb();
}
document.getElementById('files').addEventListener('change', function(e){handleFileSelect(e, function(){alert('all done');})}, false);​

打破它 - 添加了一个额外的参数,handleFileSelect并在最后添加if(cb) cb();。这只是检查 cb 是否存在,如果存在,则将其作为函数运行。

然后,当我们去绑定事件处理程序而不是传递对我们的引用时,handleFileSelect我们使用了一个匿名函数——这让我们可以传递额外的参数。

匿名函数内部的匿名函数只是我们的回调,如果您愿意,它可以是对函数的引用。

于 2012-12-06T17:21:51.490 回答
1

一个非常干净的方法是使用async.js reduce方法。 Async.js提供了许多很好的方法来处理多个回调。您可以使用 reduce 遍历文件名数组,并构建一个缩减值,该值是有效行的数组:

<input type="file" id="files" name="files[]" multiple />
<script type='text/javascript' src='https://github.com/caolan/async/raw/master/lib/async.js'/>
<script>
var isValidLine = function(text){
// todo: implement
}

function handleFileSelect(evt) {
    var files = evt.target.files; // FileList object
    // reduce by starting with empty array in second argument - 
    // this gets built up with the valid array lines
    async.reduce(files, [], function(validLinesSoFar, file, callback){
        var r = new FileReader();
        // Read file here:
        r.onload = function (f) {

            var contents = f.target.result;
            var lines = contents.split('\n');

            for(var i=0; i<lines.length; i++){
                if isValidLine(lines[i])
                    validLinesSoFar.push(lines[i]);    
            }
            callback(null, validLinesSoFar); 
        };

        r.readAsText(file);
    }, function(err, validLines){
        // gets called after every file iterated through
        // result is entire valid array
        // do something here with valid array
    });
}

  document.getElementById('files').addEventListener('change', handleFileSelect, false);
</script>
于 2012-12-21T18:55:30.470 回答
0

我会看看jQuery的延迟对象

也是一个可能适用于您的非常相关的问题。

在Jquery中完成for循环后如何触发回调函数?

于 2012-12-06T17:21:29.260 回答