Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

257
Views
Problem with drawing image on canvas after loading it with fetch and async/await

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>

about 4 years ago · Juan Pablo Isaza
2 answers
Answer question

0

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 fetch here, you can very well just set the image's .src to the URL directly:

const canvas = document.body.querySelector("canvas");
const ctx = canvas.getContext("2d");

// Displaying image element in HTML works.
const img = document.body.querySelector("img");
img.crossOrigin = "anonymous"; // allow read-back
img.src = "https://avatars.githubusercontent.com/u/92330684?s=120&v=4";
img.onload = (evt) => // or await img.decode() if in async
  ctx.drawImage(img, 0, 0);
canvas {
   border: 1px solid #000;
}
<canvas></canvas>
<img>

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 in drawImage()).
For older browsers that didn't support this method, I got you covered through this polyfill of mine.

async function loadImage(url) {
  const response = await fetch(url);
  const blob = response.ok && await response.blob();
  return createImageBitmap(blob);
}

const canvas = document.body.querySelector("canvas");
const ctx = canvas.getContext("2d");
loadImage("https://avatars.githubusercontent.com/u/92330684?s=120&v=4").then((bitmap) => {
  ctx.drawImage(bitmap, 0, 0);
});
canvas {
   border: 1px solid #000;
}
<!-- createImageBitmap polyfill for old browsers --> <script src="https://cdn.jsdelivr.net/gh/Kaiido/createImageBitmap/dist/createImageBitmap.js"></script>
<canvas></canvas>
<!-- HTMLImage is not needed -->

*It may happen that cached images are ready before the next call to drawImage(), but one should never assume so.

about 4 years ago · Juan Pablo Isaza Report

0

Even though you're using an in-memory blob URL, it still needs to be loaded by the browser.

You aren't waiting for the img to load before adding it to the canvas so all it adds is a blank.

Register a load event handler or use the newer HTMLImageElement.decode() to wait for the image to be ready before adding it to the canvas.

async function loadImage(url) {
  let response = await fetch(url);
  let blob = await response.blob();
  return URL.createObjectURL(blob);
}

const img = document.querySelector("img");
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");

const url = "https://avatars.githubusercontent.com/u/92330684?s=120&v=4"

loadImage(url).then(async (tileURL) => {

  // Displaying image element in HTML works.
  img.src = tileURL;
  
  // wait for it to load
  await img.decode()
  
  ctx.drawImage(img, 0, 0);
});
canvas {
  border: 1px solid #000;
}
<canvas></canvas>
<img>

about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!