75

Temp.js

export default class Temp {
    async addImageProcess(src){
        let img = new Image();
        img.src = src;
        return img.onload = await function(){
          return this.height;
        }
    }
}

anotherfile.js

import Temp from '../../classes/Temp'
let tmp = new Temp()

imageUrl ="https://www.google.co.in/images/branding/googlelogo/2x/googlelogo_color_120x44dp.png"
let image = tmp.addImageProcess(imageUrl);
console.log(image)

Above is my code. I have a image url and tried to get image's properties using async await but it's not working, don't understand what I missed.

3 Answers 3

121

Your problem here extends from the definition for await...

The await operator is used to wait for a Promise

The Image.prototype.onload property is not a promise, nor are you assigning it one. If you're wanting to return the height property after loading, I would instead create a Promise...

addImageProcess(src){
  return new Promise((resolve, reject) => {
    let img = new Image()
    img.onload = () => resolve(img.height)
    img.onerror = reject
    img.src = src
  })
}

You would then use the following to access that value

tmp.addImageProcess(imageUrl).then(height => {
  console.log(height)
})

or, if within an async function

async function logImageHeight(imageUrl) {
  console.log('height', await tmp.addImageProcess(imageUrl))
}
1
  • 3
    thanks @phil, now I understood. There is a small typo in addImageProcess.
    – Rahul
    Commented Sep 25, 2017 at 7:36
103

Previous answers are correct, but I wanted to point out that there is now an HTMLImageElement.decode() method which almost corresponds to a Promisified onload handler.

This has the advantages of not needing to do the wrapping yourself, to handle already loaded images (previous answers fail this case), and to wait for the image to be actually decoded, which may be a good thing in various situation (e.g if you wanted to use it with the synchronous Canvas2DContext.drawImage() method, your script would get blocked while this decoding is done).

So now all it takes is

(async () => {
  const img = new Image();
  img.src = "https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png";
  await img.decode();
  // img is ready to use
  console.log( `width: ${ img.width }, height: ${ img.height }` );
})();

6
  • 1
    Note for those who are looking to use this, decode() is incompatible with IE
    – stor314
    Commented Jan 14, 2022 at 15:51
  • 22
    @stor314 and IE is incompatible with humans. Commented May 15, 2022 at 13:24
  • 2
    @AkshayKNair i agree, wish clients would understand that
    – stor314
    Commented May 16, 2022 at 14:32
  • 1
    this perfectly solved my problems, all my thanks Commented Dec 7, 2022 at 13:46
  • This is the cleanest way to achieve async await with images loading in modern browsers, thanks @adrianosmateus Commented Aug 23, 2023 at 15:44
20

While the proposed solution works perfect, I want to be able to avoid writing promises for every asynchronous function, so I wrote a generic utility function just for this purpose:

in javascript

function onload2promise(obj){
    return new Promise((resolve, reject) => {
        obj.onload = () => resolve(obj);
        obj.onerror = reject;
    });
}

in typescript (including some generic typechecks):

interface OnLoadAble {
   onload: any;
}
function onload2promise<T extends OnLoadAble>(obj: T): Promise<T> {
   return new Promise((resolve, reject) => {
   obj.onload = () => resolve(obj);
   obj.onerror = reject;
 });
}

In the example of the question, you can now do:

async function addImageProcess(src){
    let img = new Image();
    let imgpromise = onload2promise(img); // see comment of T S why you should do it this way.
    img.src = src;
    await imgpromise;
    return this.height;
}

Off course, the call in anotherfile.js should still happen asynchronously as well, as explained in the last codeblock of Phils answer

4
  • 1
    The Promise never rejects. Set onerror: function onload2promise(obj){ return new Promise((resolve,reject) => { obj.onload = () => resolve(obj); obj.onerror = reject; }); }
    – T S
    Commented Aug 1, 2019 at 18:49
  • 2
    Your method is slightly dangerous: It sets onload after image loading started. See stackoverflow.com/questions/14648598/…
    – T S
    Commented Aug 1, 2019 at 18:50
  • Good remarks, I think I updated the answer to fix the issues you mentioned!
    – Pinna_be
    Commented Aug 6, 2019 at 7:47
  • Nice! Some more thoughts: Should onabort also reject the Promise? The interface OnLoadAble should contain onerror (and onabort if added as reject event). In your last Codeblock, did you mean return img.height;?
    – T S
    Commented Aug 6, 2019 at 10:48

Not the answer you're looking for? Browse other questions tagged or ask your own question.