我是javascript的新手,而且这个问题困扰了我好几天了。我有成千上万张图像(统称为“数据集”),当快速查看一个接一个时,就会显示出视频的外观。我想遍历所有图像。
我已经创建了一个像这样的函数:
function updateImage(dataset, record_id) {
image_url = '/image?dataset='+dataset+'&record-id='+record_id;
if ($('#mpeg-image').length > 0) {
$('#mpeg-image')[0].src = image_url;
} else {
$("#image-thumbnail").html('<img id="mpeg-image", src="'+image_url+'"> </img>');
}
}
调用函数一次,例如updateImage('dataset_28_18-08-11',444);
会导致浏览器中的图像内容更新。但是,我想循环显示图像,所以我创建了一个像这样的函数:
function playVideo() {
for (i = 0; i < 1800; i++) {
updateImage(dataset,i);
}
}
此函数使用与上面相同的updateImage()
函数,但是当我运行playVideo();
时,Chrome直到最后才更新图像。 src
标签会更改,但实际内容不会更改。如何更改循环,以便依次加载和显示每个图像?我不想使用“ Sprite”之类的东西将所有图像合并到一个图像中,因为这在我的后端会占用大量数据。我只想一个接一个地加载并显示图像。
答案 0 :(得分:1)
在代码执行中断之前,浏览器不会重新渲染页面元素。整个图像循环将在浏览器获得重新绘制图像的机会之前运行。
这不是因为循环“运行得太快”或不是图像没有加载(尽管这肯定会带来问题)。要查看重绘问题的示例,请尝试将动画更改为无限循环并连续播放。页面将永久冻结(“风车”),并且页面元素将永远不会更新,即使在加载所有图像后很长时间也是如此。每当您对页面元素进行更改时,都需要让浏览器有机会重绘页面。
在网络动画中,这通常是通过window.requestAnimationFrame()
完成的(请参见MDN docs)。该方法采用回调函数,该函数在浏览器重绘页面后执行。准备更改页面后,浏览器将执行您的回调。
一个与您的代码有关的简单示例就是这样。
var imageNo = 0;
function step() {
updateImage(dataset, imageNo);
imageNo++;
if (imageNo < 1800) {
window.requestAnimationFrame(step);
}
}
window.requestAnimationFrame(step);
使用setTimeout()
或setInterval()
可以达到类似的效果,但是这些方法并未针对动画进行优化。
答案 1 :(得分:0)
之所以只看到最后一张图片,是因为两件事。
1.如@andriusain所说,浏览器下载每个图像花费的时间不确定。
2.循环运行得如此之快,以至于最后一次迭代才生效。
话虽如此,最好是对图像进行精灵处理(听起来像是做不到的),或者可以预加载图像,以便浏览器缓存它们,然后设置URL。您可以执行以下操作。
// using es6
// I'd recommend adding <img src="mpeg-image" /> to your html page
// just to simplify the code. Also I recommend saving the image
// element in a local variable instead of using jQuery in each
// iteration loop which will definitely give a slower performance.
const mpegImgElement = $('#mpeg-image')[0];
const FPS = 30 / 1000; // 30 Frames Per Second
function playVideo() {
preLoadImages()
.then(urls => {
playUrls(urls);
})
.catch(error => {
console.log('error loading images', error);
})
}
function playUrls(urls) {
const index = 0;
const intervalId = setInterval(() => {
// set the url
mpegImgElement.src = urls[index];
// all done. stop the interval
if (++index === urls.length) {
clearInterval(intervalId);
}
}, FPS);
}
function preLoadImages() {
const promises = [];
for (i = 0; i < 1800; i++) {
const imageUrl = '/image?dataset='+dataset+'&record-id='+record_id;
const promise = loadImage(imageUrl);
promises.push(promise);
}
return Promise.all(promises);
}
function loadImage(url) {
return new Promise((resolve, reject) => {
const image = new Image();
image.addEventListener('load', () => {
resolve(url);
});
image.addEventListener('error', error => {
reject(error);
});
image.src = url;
});
}
答案 2 :(得分:-1)
发生这种情况是因为浏览器仍在加载图像...我认为最好的选择是先以编程方式加载它们,一旦加载它们,然后播放视频...这样做可能会有所帮助:< / p>
var loadImages = function(images, callback) {
var loadTotal = 0;
for (var i = 0; i < images.length; i++) {
var image = new Image();
image.addEventListener('load', function() {
loadTotal++;
if (loadTotal === images.length) {
callback();
}
});
image.src = images[i];
}
}
var playVideo = function() {
// do stuff...
}
var images = ['image1.jpg', 'image2.jpg'];
loadImages(images, playVideo);
答案 3 :(得分:-1)
这个主意太可怕了。
JS在单线程中执行,而从src调用数据是异步方法。一次调用一次,然后等待,然后肯定会阻塞线程。
在这种情况下,您需要保证先准备好所有图像。
我使用Google徽标制作了一个可行的示例。
paths = ["https://www.google.com.hk/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png",
"https://www.google.com.hk/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png",
"https://www.google.com.hk/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png"]
var imgCount = paths.length;
function loadImage(url) {
return new Promise((resolve, reject) => {
let img = new Image();
img.addEventListener('load', e => resolve(img));
img.src = url;
});
}
promises = []
for (var i = 0; i < paths.length; i++){
path = paths[i];
promises.push(loadImage(path));
}
Promise.all(promises).then(imgs => {
imgs.forEach(e => document.getElementById('image-holder').appendChild(e));});
//What I done here is display then all, but you can make it like, replace one by one, or declare your own display function.
<div id="image-holder"></div>