2

jpeg画像をフレームごとに読み込んで、jpeg画像のシーケンスアニメーションを作成しようとしています。javascriptを使用して再帰ループでそれらをロードしようとしています。アニメーションのプログレッシブ再生を実現するには、画像を直線的に読み込む必要があります。(すべてのフレームがロードされる前に再生を開始します)関数Stack overflow at line: 0の自然な再帰が原因でIEからエラーが発生します。(私の実際のコードは60以上のフレームでロードされます)

これが私がこれを行う方法の基本的な例です:

var paths = ['image1.jpg', 'image2.jpg', 'image3.jpg']; //real code has 60+ frames
var images = [];
var load_index = 0;

var load = function(){
    var img = new Image();
    img.onload = function(){
        if(load_index<=paths.length){
            load_index++;
            load();
        }else{
            alert('done loading');
        }
    }
    img.src = paths[load_index];
    images.push(img);
}

ロードの次のステップを呼び出すときに、間隔1のsetTimeoutを使用することで、このエラーを回避できるようです。これにより、IEは次の画像を読み込む前に「呼吸」できるように見えますが、画像の読み込み速度が大幅に低下します。

このスタックオーバーフローエラーを回避する方法を知っている人はいますか?

http://cappuccino.org/discuss/2010/03/01/internet-explorer-global-variables-and-stack-overflows/

上記のリンクは、関数をラップしてウィンドウオブジェクトから削除すると、スタックオーバーフローエラーを回避するのに役立つことを示しています。しかし、その後、シーケンス全体で約15フレームしか取得できず、ただ死んでしまうという奇妙なことがわかります。

4

1 に答える 1

0

簡単に言えば、この状況では再帰関数を使用しないでください。必要はありません。

var paths = ['image1.jpg', 'image2.jpg', 'image3.jpg'];
var images = [];
var loads = [];

/// all complete function, probably should be renamed to something with a 
/// unique namespace unless you are working within your own function scope.
var done = function(){
  alert('all loaded');
}

var loaded = function(e,t){
  /// fallbacks for old IE
  e = e||Event; t = e.target||e.srcElement;
  /// keep a list of the loaded images, you can delete this later if wanted
  loads.push( t.src );
  if ( loads.length >= paths.length ) {
    done();
  }
}

var load = function(){
  var i, l = paths.length, img;
  for( i=0; i<l; i++ ){
    images.push(img = new Image());
    img.onload = loaded;
    img.src = paths[i];
  }
}

実際、お気づきのように、現在使用している方法は非常に集中的です。onload代わりに、上記のバージョンはリスナーごとに新しい関数を作成せず(メモリを節約します)、ブラウザーが許可する限り多くの同時読み込みをトリガーします(各画像の読み込みを待機するのではなく)

(上記は手動で入力されており、まだテストされていません)

アップデート

ああ、なぜこのようにしているのかについては、もっと理にかなっています:)その場合、 を使用した最初のアプローチsetTimeoutがおそらく最良の解決策になります(タイムアウトを使用できるはずです0)。ただし、それを回避できるかどうかを確認するために、物事を再配置する余地はまだあります。以下は問題を回避するかもしれません...

var paths  = ['image1.jpg', 'image2.jpg', 'image3.jpg'];
var images = []; /// will contain the image objects
var loads  = []; /// will contain loaded paths
var buffer = []; /// temporary buffer
var done   = function(){ alert('all loaded'); }

var loaded = function(e,t){
  e = e||Event; t = e.target||e.srcElement; loads.push( t.src );
  /// you can do your "timing/start animation" calculation here...
  /// check to see if we are complete
  if ( loads.length >= paths.length ) { done(); }
  /// if not fire off the next image load
  else { next(); }
}

var next = function(){
  /// current will be the next image
  var current = buffer.shift();
  /// set the load going for the current image
  if ( current ) { current.img.src = current.path; }
}

var load = function(){
  var i, l = paths.length, img;
  for( i=0; i<l; i++ ){
    img = new Image();
    img.onload = loaded;
    /// build up a list of images and paths to load
    buffer.push({ img: img, path: paths[i] });
  }
  /// set everything going
  next();
}

上記の方法で解決しない場合、問題を回避する別の方法として、パスのリストを 1 つずつ調べて、DOM にイメージ マークアップの文字列 (画面外にレンダリングされる) を追加します。それは独自のonload="next()"ハンドラーです...next()次の画像を挿入する責任があります。これを行うことで、ロードのトリガーとそれに続くロード イベントをコードの外部に渡し、呼び出しのスタックを回避する必要があります。

于 2012-12-12T23:06:16.770 に答える