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();
}

如果上述方法没有做到这一点,另一种解决问题的方法是单步执行您的路径列表,一次一个,然后将一串图像标记(将在屏幕外渲染)附加到 DOM它是自己的onload="next()"处理程序......next()将负责插入下一张图片。通过这样做,它将触发加载和随后的加载事件到您的代码之外,并且应该绕过堆栈调用。

于 2012-12-12T23:06:16.770 回答