Javascript 首次在Chrome中绘制大型图像时的小延迟
我正在使用canvas标记开发一个简单的基于JavaScript的游戏。作为游戏的一部分,我有几个大精灵表(例如2816x768和4096x4864),每个都包含屏幕角色的相关动画。当游戏开始时,游戏只是播放角色的空闲动画。当用户按下空格键时,我开始播放另一个完全不同的动画 以下是绘制精灵的代码:Javascript 首次在Chrome中绘制大型图像时的小延迟,javascript,google-chrome,canvas,Javascript,Google Chrome,Canvas,我正在使用canvas标记开发一个简单的基于JavaScript的游戏。作为游戏的一部分,我有几个大精灵表(例如2816x768和4096x4864),每个都包含屏幕角色的相关动画。当游戏开始时,游戏只是播放角色的空闲动画。当用户按下空格键时,我开始播放另一个完全不同的动画 以下是绘制精灵的代码: Sprite.prototype.drawFrame = function(x, y) { ctx.drawImage(this.image, x*this.width, y*
Sprite.prototype.drawFrame = function(x, y)
{
ctx.drawImage(this.image,
x*this.width, y*this.height,
this.width, this.height,
this.position[0], this.position[1],
this.width, this.height);
};
下面是加载图像的代码:
Stage.prototype.loadImage = function(src)
{
var image = new Image();
this.incAssets();
var stage = this;
image.onload = function()
{
stage.decAssets();
}
image.src = src;
return image;
}
问题在于,从用户按下空格键到新精灵图纸中的帧实际绘制时,会有1.5秒的延迟。这只是一次,不会影响后续动画的平滑度。我已经使用新图像
预加载了精灵表,在所有相应的Image.onload事件触发之前,游戏甚至不会启动,因此我知道浏览器不会等待加载。我已经使用Chrome17.0中的调试器逐步了解了JavaScript,并将延迟缩小到上下文上的drawImage
调用。最令人困惑的是,Firefox10.0.2中没有出现这种延迟,因此这是一个Chrome特有的问题。这对游戏造成了很大的干扰
我做错了什么?我是否可以减少Chrome的延迟
编辑:我尝试按照Peter Wishart的建议,在加载下一帧后立即绘制整个帧,但效果甚微。我还尝试修改loadImage
,如下所示:
Stage.prototype.loadImage = function(src)
{
var image = new Image();
this.incAssets();
var stage = this;
image.onload = function()
{
ctx.drawImage(image, 0, 0);
stage.decAssets();
}
image.src = src;
return image;
};
这也没有效果
事实上,我确实找到了一个解决方案,但效率非常低。我突然想到Chrome在解码后可能会尝试用图像内存做一些聪明的事情。如果一个图像被闲置足够长的时间,而这又只是一个猜测,Chrome将从内存中删除解码后的数据,并在需要时将其拉回到内存中。通常情况下,解码过程需要花费不明显的时间,但我使用的大图像会导致性能出现非常剧烈的波动。使用此选项,我将绘制循环更改为:
function draw()
{
var currentTime = new Date().getTime();
var deltaTime = currentTime - lastTime;
lastTime = currentTime;
var dt = deltaTime / 1000.0;
// The hack that keeps all decoded image data in memory is as following.
if (this.stage.nextStage != undefined)
this.stage.nextStage.draw(0); // The 0 here means the animations advance by 0 milliseconds, thereby keeping the state static.
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(backgroundImage, 0, 0, canvas.width, canvas.height);
if (stage != undefined && stage.loaded)
{
stage.draw(dt);
}
}
这个解决方案确实有效,但正如我所说,这似乎是一种可怕的浪费。我必须绘制下一组动画的整个帧,只是为了防止解码数据在Chrome中过时
有没有比这一策略更不浪费、更不刻薄的替代方案?嗯。。虽然onLoad已经启动,但Chrome可能需要做一些事情来准备图像,比如解压缩、加载到图形卡
你能强迫第一帧先离开屏幕或隐藏,以便在用户按下空格键之前将延迟移动吗?考虑到Chrome只是在一段时间后扔掉解码的图像数据,我尝试将图像复制到屏幕外的画布上,假设Chrome不会费心从内存中取出画布。执行此操作的代码非常适合
loadImage
函数
Stage.prototype.loadImage = function(src)
{
var useCanvasCache = Prototype.Browser.WebKit; // If we are in a WebKit browser (e.g. Chrome)
var decodeCanvas;
var dectodeCtx;
if (useCanvasCache)
{
// Creates a canvas to store the decoded image.
decodeCanvas = document.createElement('canvas');
dectodeCtx = decodeCanvas.getContext('2d');
}
var image = new Image();
this.incAssets();
var stage = this;
image.onload = function()
{
stage.decAssets();
// Simply transfer the image to the canvas to keep the data unencoded in memory.
if (useCanvasCache)
{
decodeCanvas.width = image.width;
decodeCanvas.height = image.height;
dectodeCtx.drawImage(image, 0, 0);
}
}
image.src = src;
// Canvas works the same as an image in a drawImage call, so we can decide which to return.
if (useCanvasCache)
{
return decodeCanvas;
}
else
{
return image;
}
};
它也有效。当页面加载时,有一个小的初始惩罚,它可能会使用更多的内存,但这是一个可行的解决方案,因为在这个应用程序中,速度比内存更重要。似乎chrome添加到
解码
功能正是为了这个目的,防止首次添加到DOM时出现解码延迟
似乎没有在firefox或IE中实现
const img = new Image();
img.src = "bigImage.jpg";
img.decode().then(() => {
document.body.appendChild(img);
}).catch(() => {
throw new Error('Could not load/decode big image.');
});
更多信息: