2

html5 filereader APIを使用して、ユーザーが写真をアップロードしなくてもローカルで写真を取得しています。

これをサポートするブラウザーでは、複数の選択を許可しているため、選択したファイルをループして、以下に示すように各ファイルで関数(TC.editor.renderSlide())を実行しています。

 handlePhotoUploads: function(event) {
    var self = this;
    TC.dialog.destroy();
    var files = event.target.files;
    var count = files.length + TC.editor.cache.slides.length;
    for (var i = 0, f; f = files[i]; i++) {
        if (!f.type.match('image.*')) {
            continue;
        }
        var reader = new FileReader();
        var index = TC.editor.getNewSlidesIndex();
        TC.editor.addNewSlide('photo', index);
        reader.onload = (function(theFile) {
            var slideindex = index;
            return function(e) {
                TC.editor.renderSlide(slideindex, e.target.result, 'internal', count);
            };
        })(f);
        reader.readAsDataURL(f);
    }
},

問題は、TC.editor.renderSlide()関数の実行にかなりの時間がかかる可能性があるため(キャンバスおよびDOM操作を実行する)、8つほどの大きな画像ファイルを処理するときにブラウザーがかなりの時間ロックされることです。'処理gifでさえ、この期間中はアニメーション化を停止します。

各reader.onloadイベントが、前のイベントが完了した後にのみ発生するようにする方法はありますか?このように、すべてが処理されている間ブラウザをロックする現在の状況ではなく、TC.editor.renderSlide()への各呼び出しの結果を個別に確認することで、ユーザーに定期的な進行状況の更新が提供されますか?

単純なsetTimeoutをrenderSlide()に追加しようとしましたが、役に立ちませんか?

どんな助けやアイデアも大歓迎です。

4

2 に答える 2

3

onloadイベントは順番に発生します。ハンドラーは、他のイベントが現在処理されている間は実行されません(「JSはシングルスレッドです」)。もちろん、これは、ハンドラーで非同期処理(タイムアウト、アニメーション、ファイルのロード)を開始する場合にはカウントされません。

その場合、順次処理を手動で行う必要があります。終了時に実行される待機中のプロセスのキューを使用するのは簡単です。

var waiting = [];
// …create many parallel loaders, and on each:
    ….onevent = execute;

function execute(e) {
    if (waiting.active)
        waiting.push(e);
    else {
        waiting.active = true
        // do something that takes its time, supplying a
          … function callback(ready) {
            waiting.active = false;
            if (waiting.length)
                execute(waiting.shift()); // go on with next
          }
    }
}

ただし、問題の原因ではないように見えますが、同時にrenderSlide非常に多くのをインスタンス化しています。FileReaderforループを非同期的に呼び出される「再帰」関数に変えて、ファイルのロードを次々に開始させます。

var files = […]
(function handle(i) {
     if (i >= files.length) return;
     // create loader
     ….onevent = function(e) {
          // do processing, and then call
          handle(i+1);
          // or call that from another callback if you want to do async
          // processing, like "renderSlide"
     };
})(0);
于 2012-10-31T21:48:58.053 に答える
2

イベント順番に発生します。Javascriptはシングルスレッドであるため、イベントハンドラーの1つが実行されている間、他のイベントは発生しません。また、そのシングルスレッドはJavascriptイベントハンドラーの実行によって占有されているため、ブラウザー*は応答しません。renderSlide()実行中setTimeoutはブラウザがロックされたままになるため、で全体を実行するだけでは不十分renderSlide()です。内部 の実際のロジックrenderSlide()を個別のチャンクに分割する必要があります。各チャンクは、を使用して延期できsetTimeout(chunk, 1)、ブラウザーに応答性を維持するための少しの余裕を与えます。

*実際には、ロックされているのはブラウザ全体ではない可能性があります。単一のスレッドで実行されている1つのタブまたは関連するタブのグループである可能性があります。実際のブラウザアーキテクチャは異なります。

于 2012-10-31T21:47:39.703 に答える