我正在制作一个小的画布动画,这需要我逐步浏览大的Sprite Sheet PNG,因此我从drawImage()中获得了很多收益。过去我从来没有遇到过麻烦,但是今天我在触发drawImage之后遇到了一个奇怪的阻塞延迟。
我的理解是drawImage是同步的,但是当我运行此代码时, drawImage已触发!大约在图像实际出现之前700毫秒。值得注意的是,在Chrome中为700毫秒,在Firefox中为1100毫秒。
def other_server():
s = eventlet.listen(('0.0.0.0', 6000))
pool = eventlet.GreenPool(5)
while True:
c, address = s.accept()
pool.spawn_n(function, c)
if __name__ == '__main__':
eventlet.spawn(other_server)
eventlet.wsgi.server(eventlet.listen(('0.0.0.0', 4000)), app)
在较大的上下文中,此代码在requestAnimationFrame循环中运行,我只在第一次执行drawImage时遇到这种延迟。
我认为这与我的Sprite Sheet的大尺寸(28000×3200)@ 600kb有关,尽管onload事件似乎可以正确触发。
edit:这是rAF帧之间的时间(毫秒)的打印输出。除非删除drawImage函数,否则我将始终获得此结果。
答案 0 :(得分:2)
这是因为加载事件仅是网络事件。它仅表明浏览器已获取媒体,解析元数据,并确认它是可以解码的有效媒体文件。
但是,触发此事件时可能仍未制作渲染部分,因此这就是为什么您要进行第一次渲染需要花费大量时间的原因。 (尽管以前它只是一种FF行为。)
由于是drawImage()
是同步的,因此也将使解码+呈现同步操作。的确如此,您甚至可以使用drawImage来告诉when an image really is ready.。
请注意,HTMLImageElement接口上现在有一个decode()
方法,它将以非阻塞方式准确地告诉我们这一点,因此最好在可用时使用它,并且无论如何都要进行预热在运行扩展的图形应用程序之前,请在屏幕上关闭所有功能。
但是,由于您的源图像是一张Sprite-sheet,因此实际上您可能对createImageBitmap()方法更感兴趣,该方法将从您的源图像生成ImageBitmap,并且可以选择将其切除。这些ImageBitmap已被解码,可以立即拖到画布上。这应该是您的首选方式,因为这样也可以避免每次绘制整个Sprite-sheet。对于不支持该方法的浏览器,您可以通过返回HTMLCanvasElement以及在其上绘制的图像部分来猴子修补它:
if (typeof window.createImageBitmap !== "function") {
window.createImageBitmap = monkeyPatch;
}
var img = new Image();
img.crossOrigin = "anonymous";
img.src = "https://upload.wikimedia.org/wikipedia/commons/b/be/SpriteSheet.png";
img.onload = function() {
makeSprites()
.then(draw);
};
function makeSprites() {
var coords = [],
x, y;
for (y = 0; y < 3; y++) {
for (x = 0; x < 4; x++) {
coords.push([x * 132, y * 97, 132, 97]);
}
}
return Promise.all(coords.map(function(opts) {
return createImageBitmap.apply(window, [img].concat(opts));
})
);
}
function draw(sprites) {
var delay = 96;
var current = 0,
lastTime = performance.now(),
ctx = document.getElementById('canvas').getContext('2d');
anim();
function anim(t) {
requestAnimationFrame(anim);
if (t - lastTime < delay) return;
lastTime = t;
current = (current + 1) % sprites.length;
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
ctx.drawImage(sprites[current], 0, 0);
}
}
function monkeyPatch(source, sx, sy, sw, sh) {
return Promise.resolve()
.then(drawImage);
function drawImage() {
var canvas = document.createElement('canvas');
canvas.width = sw || source.naturalWidth || source.videoWidth || source.width;
canvas.height = sh || source.naturalHeight || source.videoHeight || source.height;
canvas.getContext('2d').drawImage(source,
sx || 0, sy || 0, canvas.width, canvas.height,
0, 0, canvas.width, canvas.height
);
return canvas;
}
}
<canvas id="canvas" width="132" height="97"></canvas>