快速加载多张图片的HTML页面

4
我正在编写一个脚本,用户可以选择数据范围,然后我从服务器获取一些图像(超过150张),然后循环遍历它们以制作类似于电影的东西。我想知道的是,在移动图像时最有效的加载方式如何避免卡顿。

目前,我使用Ajax从服务器获取图像,并将它们存储在JavaScript中的Image对象数组中。在HTML中,我希望将这些图像放入一个div标签中。在我完成创建数组中所有Image对象并设置其正确的src之后,我执行以下操作:

imgElem = document.createElement('img');
document.getElementById('loopLocation').appendChild(imgElem);
imgElem.src = images[0].src;

之后,我只需更改循环索引,并在每400毫秒执行一次该最终调用。该循环可以工作,但有时会出现滞后情况,并且会在一个图像上冻结的时间比预期的要长。我想知道是否能够从客户端进一步改善此问题,或者我是否需要一个响应更快的服务器。


嗯,你在循环中展示图片之前预加载所有的图片怎么样?或者由于某些原因这不是一个选项? - hndcrftd
在展示它们之前,我会将它们放入数组中。 - Sednus
1
是的,请查看我下面发布的链接,有一种方法可以在所有图像成功加载到浏览器缓存后运行脚本,这将使循环避免“即时”加载它们。 - hndcrftd
我想要指出的是,你运行代码来预加载图像,它们开始在后台预加载,但是当你进入“循环”函数并且循环开始执行时,并不是所有的图像都已经成功预加载,因此你会从像Joseph发布的那样的预加载脚本中受益。 - hndcrftd
2个回答

6
你可能想考虑 精灵图,将所有图片放入一个大图中。这样,你只需要加载一个大图,然后为每个场景重新定位即可。
或者,在实际使用这些 150 张图片之前,你可能还想预加载它们。你可以使用 JS 数组来存储 Image 对象,然后通过循环该数组来获取你的图片。
var images = [];
var expectLoaded = 150;

for(var i = 0; i<expectLoaded;i++){
    (function(i){

        //new image object
        var img = new Image();

        //onload hander
        img.onload = function(){

            //after load, push it into the array
            images.push[img];

            //and check if the all has loaded
            if(images.length === expectLoaded){
                //preload done
            }
        }

        //start loading this image
        img.src = //path to image[i];

    },(i));
}

循环阻塞UI线程。JS是单线程的,意味着代码按照线性方式执行,一个接一个地执行。在循环语句之后的任何内容都将等待循环完成。如果那个循环需要很长时间……就去喝杯咖啡吧。此外,由于你正在操作DOM,因此由于UI线程被阻塞,你看不到更改。
但有方法可以绕过这一点,其中之一是使用超时来延迟和排队代码以供稍后执行,当JS没有忙碌时。
function animate(frameNo){

    //animate frame[frameNo];

    if(frameNo < total_frames){    //make the UI breate in between frames
        setTimeout(function(){   //so that changes reflect on the screen
            animate(++frameNo);  //then animate next frame
        },200);                  
    }
}

//start
animate(0);

1
所以你有图像,问题是帧率? - Joseph
1
嗯,有点像精灵图。 - Aram Kocharyan
2
如果你正在进行这种“动态图像”的操作,最好在画布上完成。这样,你就不会对DOM造成太大的压力。操纵DOM是一项密集的任务。 - Joseph
1
我认为问题在于我没有使用onload事件处理程序。我会尝试一下。谢谢。 - Sednus
1
循环会阻塞UI线程。当循环正在进行时,您无法执行任何操作。如果这样做,效果将会很卡顿。相反,使用由setTimeout延迟的自调用函数,以便UI在调用之间可以呼吸。 - Joseph
我很惊讶这个答案里有一个错别字,而且已经存在了9年?你没有将i传递给lambda,而是使用逗号运算符来分隔操作数,就像(f, (i));一样。 :) - bambams

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接