Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

250
Visualizações
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 Respostas
Responde à pergunta

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 Relatório

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 Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda