I tried to load image using fetch and async/await and display it on canvas, but it doesn't work. The image isn't drawn on canvas. It loads correctly into img element in HTML. On canvas if I wrap the drawing code in setTimeout it works, but I would prefer to not to do this.
Is there some way to load the image using await and fetch and draw it on canvas without setTimeout?
Here is the code:
async function loadImage(url) {
let response = await fetch(url);
let blob = await response.blob();
return URL.createObjectURL(blob);
}
let canvas = document.body.querySelector("canvas");
let ctx = canvas.getContext("2d");
let tileURL = loadImage("https://avatars.githubusercontent.com/u/92330684?s=120&v=4").then((tileURL) => {
// Displaying image element in HTML works.
let img = document.body.querySelector("img");
img.src = tileURL;
// Displaying the image immediately in canvas doesn't work.
ctx.drawImage(img, 0, 0);
// But it works if I add some delay.
setTimeout(() => {
ctx.drawImage(img, 100, 0);
}, 3000); // 3 second delay.
});
canvas {
border: 1px solid #000;
}
<canvas></canvas>
<img>
Loading an image is always asynchronous, whatever the source*. You need to wait for it has loaded before being able to do anything with it.
Now, it's unclear why you are using
fetchhere, you can very well just set the image's.srcto the URL directly:However, if you have a Blob (or are actually forced to use
fetch), then create an ImageBitmap from this Blob directly. This is the most performant way to produce and store a CanvasImageSource (to be used indrawImage()).For older browsers that didn't support this method, I got you covered through this polyfill of mine.
*It may happen that cached images are ready before the next call to
drawImage(), but one should never assume so.