I want to draw a rectangle on an HTML5 canvas
, and have it move based on coordinates originating from an asynchronous source. I used setTimeOut
to simulate the asynchronous source:
async function getX() {
return new Promise((resolve) => {
setTimeout(() => {
resolve(Math.random() * canvas.width);
}, 500);
});
}
async function animate() {
requestAnimationFrame(animate);
ctx.clearRect(0, 0, canvas.width, canvas.height);
const x = await getX();
ctx.strokeRect(x, 100, 200, 100);
}
animate();
However, this doesn’t seem to work. Trying to draw it without animating (i.e. – without using requestAnimationFrame()
), works, so I believe the problem arises from some "collision" between frames wanting to move forward and the async function.
How could I fix this?
2
Answers
The problem is a race condition between requestAnimationFrame(animate) which calls animate before the next frame and getX which stalls the method for 500 ms. Resulting in ctx.clearRect being called at least one time before each frame.
You can avoid the race condition by rearranging your code like this:
I would use
setInterval
instead ofsetTimeout
that should simplify a lot in your code, also you are already using global variable I would add those elements you are drawing as globals as well…Here is an example with a bit more complexity
You can see see I have two variables
bricks
andcircle
, I still do all the drawing like you in the animate function, but I added a couple of new functions to update the position of the elements.