0

I am making a function on Ionic 3 to load user avatar with cache and a default avatar if user did not upload his own avatar. Here is my code follow by this https://gist.github.com/pabloleonalcaide/1e8ece835ea689894dd37a44f0ce7134

public get_UserIcon(id, cache = null) {
    cache = cache || Math.floor(new Date().getMinutes() / 6); //cache for 10 minutes
    let url = `${server}UserIcon${id}.jpg?c=${cache}`;
    let image = new Image();
    image.src = url;
    if(image.width != 0){ // check if image exist
      return url;
    }else{
      return DefaultImage;
    }
  }

However, when i try to run the code, the image.width will show 0 and return the Default image even the image is on the server . Sometime it will show the correct width and return the correct avatar.

I have tried to use

img.onload = () => { 
 return url;
}
img.onerror = () =>{
 return DefaultImage;
}

But i am not sure why using above code will let my app lag, it seem like stuck in the JS runtime stack. I have tried to put a console.log in both onload and onerror but none is been called.

Anyone know how to solve it? Thanks

Update:

My usage would be like this, so that the function will check is the image exist and return the user avatar or a default avatar.

<img [src]="get_UserIcon(id)">
garyc2232
  • 65
  • 2
  • 8
  • Added a [new link](https://stackoverflow.com/questions/16349578/angular-directive-for-a-fallback-image) to a Q/A about the X of your X-Y problem. – Kaiido Mar 11 '19 at 06:56

2 Answers2

1

Because loading an Image (like any resource) is an asynchronous task.

At the time you ask for the width of the Image, the request to the server may not even have left your network card, while the browser needs to have a Response from said server, and to be able to decode it and parse the metadata of the media.

You will have to wait for the image has loaded in order to have this information:

var img = new Image();
img.src = 'https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png';
console.log('before', img.width);
// wait for the iamge has loaded
img.onload = e => console.log('after', img.width);

And thus your function should embrace the asynchronicity of the task, for instance by returning a Promise:

const DefaultImage = 'default'
function get_UserIcon(id, cache = null) {
    cache = cache || Math.floor(new Date().getMinutes() / 6); //cache for 10 minutes
    const url = "https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png";
    const image = new Image();
    return new Promise((res, rej) => {
      image.onload = e => res(url); // if onload fires, width is not 0
      image.onerror = e => res(DefaultImage);
      image.src = url;
    });
  }
  
get_UserIcon().then(console.log);
Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • Yes i have tried this but i am not sure why the app will be lag and stuck. Alos i have tried to put a console.log() inside the onload and onerror function, but they are not being called. – garyc2232 Mar 11 '19 at 06:46
0

I'm not sure if I'm reading it correctly. But this block:

if(image.width != 0){ // check if image exist
  return url;
}else{
  return DefaultImage;
}

Should be inside your image.onload function. Otherwise the width is going to be 0 every time as you haven't given it any time to load the image.

Instead of returning the url, you should be calling some kind of callback function too. It's returning the url to essentially nothing.

Here's a simple fiddle to show you what I mean: https://jsfiddle.net/2sLu641j/

PixelTom
  • 11
  • 3
  • Yes but (image.width !=0 ) is just for checking the image is exist on the server. So if not exist then return the default image. My original code is Angular code like – garyc2232 Mar 11 '19 at 06:43