2

私はhttp://www.html5rocks.com/en/tutorials/file/dndfiles/に似たようなことをしています

私がやっていることは、選択したファイルの内容を一度に1つずつ読み取って、それらの行が正規表現テストに合格したことを検証することです。すべてのファイルの検証が完了したら、それに応じていくつかのボタンを更新(有効化/無効化)する必要があるため、コールバック機能

すべてが読み取られた後に何かを実行するコールバック関数を持つことは可能ですか?

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 に答える