1

I am trying to predetermine is a given url is a valid image or not. In JS, it would be ideally look like

if (isValidImg(url)){
    ...add image DOM
} else { ... discard...}

Given img.src is happening asynchronously, how can I synchronously know if the url is a valid image?

Valid meaning exist, and has a image related format or mime type.

"http://google.com/fake.img" is not valid

"http://cdn.sstatic.net/stackoverflow/img/sprites.svg?v=a7723f5f7e59" is valid

Egg_Egg
  • 177
  • 1
  • 11
  • 5
    *"how can I synchronously know if the url is a valid image"* You can't. You cannot eat the pizza before it was delivered. – Felix Kling Jan 13 '16 at 16:23
  • You can make synchrous ajax request to server to `url` and there check if it is image or not and do other stuff synchronously, but be aware to no suspend your main thread – Epsil0neR Jan 13 '16 at 16:23
  • Please define "valid". – Bergi Jan 13 '16 at 16:24
  • 3
    @Epsil0neR Except synchronous ajax [is in the process of being deprecated](https://xhr.spec.whatwg.org/#sync-warning), it's best avoided. – James Thorpe Jan 13 '16 at 16:27
  • The browser is not built for synchronous network IO requests because they tend to lead to a bad user experience, so I'd suggest you spend more of your effort on reworking your approach and code so you can use an asynchronous request to validate an image URL. – jfriend00 Jan 13 '16 at 16:40
  • When you decide to do this operation asynchronous, here is some code on validating an image asynchronously: [Javascript Image Url Verify](http://stackoverflow.com/questions/9714525/javascript-image-url-verify/9714891#9714891) – jfriend00 Jan 13 '16 at 16:42
  • I should actually add that while it's kind of annoying to formulate, it's a good idea to have whatever server request gave you the URL of the image also give you its width and height (especially if it was the initial HTML document request) to fill the `` attributes. This causes the page layout to remain relatively constant as content is filled in. – Katana314 Jan 13 '16 at 16:52

2 Answers2

0

It would be completely crazy to do that synchronously, but you can do it asynchronously. In a modern browser, or using a Promise shim/library in any browser, you can do this:

function isValidImg( url ) {
    return new Promise( function ( resolve, reject ) {

        var image = new Image;

        image.onload = function ( ) { resolve( image ) };
        image.onerror = image.onabort = reject;

        image.src = url;
    } );
}

Adapted from jfriend00's answer here, which will work in any browser without needing a Promise library. Then use it like this:

isValidImg( url ).then( function ( image ) {
    // Add image to DOM
}, function ( event ) { 
    // Handle error
    // Note: This will be reached when the image fails to load
    //       whether that be because it's not a valid image or 
    //       any other reason.
} );
Community
  • 1
  • 1
Paul
  • 139,544
  • 27
  • 275
  • 264
  • 1
    I'd revise the second example to: `isValidImg( url ).then( function ( image ) {/*add image*/}, function() { /*report to user or page that image is invalid*/ } );` since the second case is the one the OP expressed interest in. – Katana314 Jan 13 '16 at 16:53
  • @Katana314 Good point. I took `** discard **` to mean do nothing, but it would at least be good to show where they would handle the error. – Paul Jan 13 '16 at 16:57
  • @Katana314 I took your suggestion into account and updated my answer. – Paul Jan 13 '16 at 17:00
-1

As the comments on your question indicate, you should try to use async requests over sync requests wherever and whenever possible.

You should send a HEAD request to the url and check the Content-Type header is a valid image type.

Asynchronous

var request = new XMLHttpRequest();
request.open('HEAD', url);
request.onreadystatechange = function()
{
    if (request.readyState == 4 && request.status == 200)
    {
        var contentType = request.getResponseHeader('Content-Type');
        if (contentType.slice(0,6) === 'image/')
            // URL is valid image
    }
};
request.send();

Synchronous (Don't do this!)

var request = new XMLHttpRequest();
request.open('HEAD', url, false);
request.send();
if (request.readyState == 4 && request.status == 200)
{
    var contentType = request.getResponseHeader('Content-Type');
    if (contentType.slice(0,6) === 'image/')
        // URL is valid image
}
trlkly
  • 681
  • 7
  • 13
Matt
  • 1,377
  • 2
  • 13
  • 26