162

Using javascript is there a way to tell if a resource is available on the server? For instance I have images 1.jpg - 5.jpg loaded into the html page. I'd like to call a JavaScript function every minute or so that would roughly do the following scratch code...

if "../imgs/6.jpg" exists:
    var nImg = document.createElement("img6");
    nImg.src = "../imgs/6.jpg";

Thoughts? Thanks!

ajtrichards
  • 29,723
  • 13
  • 94
  • 101
0xhughes
  • 2,703
  • 4
  • 26
  • 38

18 Answers18

255

You could use something like:

function imageExists(image_url){

    var http = new XMLHttpRequest();

    http.open('HEAD', image_url, false);
    http.send();

    return http.status != 404;

}

Obviously you could use jQuery/similar to perform your HTTP request.

$.get(image_url)
    .done(function() { 
        // Do something now you know the image exists.

    }).fail(function() { 
        // Image doesn't exist - do something else.

    })
ajtrichards
  • 29,723
  • 13
  • 94
  • 101
  • does anyone know how to avoid the HEAD error message that appears in the console on any browser? I wish to run this script without their being an error if the image does not exist. Thanks – cwiggo Jan 08 '15 at 15:28
  • @ Chris try{http.open('HEAD', image_url, false); http.send();}catch{} – CoR Jun 11 '15 at 14:54
  • 6
    But shouldn't function name be fileExists because this works on .js .css .html or any other publicly available file. – CoR Jun 11 '15 at 14:56
  • Yes you can call the function whatever you want - but the original question referred to checking if an image existed so I used `imageExists(image_url)` – ajtrichards Jun 12 '15 at 07:50
  • 1
    Function is awesome. I put it in my collection :) I thought `fileExists` would be better name because this function does not check if image exists on server. It check if file is accessible from server. There is no check if that file actually is an image. It could be .pdf, .html, some random file renamed to *.jpg or *.png. If something ends with .jpg it doesn't mean it's 100% image :) – CoR Jun 16 '15 at 09:53
  • 11
    This will fail unless accessing the resource is permitted under CORS rules. Using an `Image` object doesn't suffer that limitation. The only advantage of this is that it won't actually download the image. – Alnitak Jul 13 '16 at 18:28
  • 8
    cross-domain issue. – Amit Kumar Aug 25 '16 at 10:41
  • 1
    I liked the simplicity of this, but Chrome throws an error because of the sync XHR being deprecated on main thread and all. I went with a jQuery ajax request in async mode instead. – oelna Apr 16 '17 at 14:33
  • this works as it says, the other problem was that it didn't update the image source. so would suggest to use the onerror, onError="this.onerror=null;this.src='imagepathwhennoimage';" – Athar Apr 16 '17 at 22:31
  • 2
    This does work, but keep in mind that it takes longer to process the request and isn't the best solution. Also it doesn't work on cross origin (definitely in chrome) so you can't use it on file:/// protocol which means no local usage. – Cameron May 20 '17 at 22:40
  • What's the error? If your doing something which isn't permitted under CORS rules then yes it will fail. – ajtrichards May 17 '18 at 07:07
  • To check if the resource is 'accessible', it would be better to use 'return http.status == 200;'. – ATH Jul 24 '20 at 18:37
  • these solution is deprecated in the meantime. You cannot use it anymore – thomas Jul 08 '21 at 11:54
  • the resource may be forbidden, access my be denied or may be errors, so the solution with 404 very bad – Igor Benikov Jan 23 '22 at 11:57
156

You can use the basic way image preloaders work to test if an image exists.

    function checkImage(imageSrc, good, bad) {
        var img = new Image();
        img.onload = good; 
        img.onerror = bad;
        img.src = imageSrc;
    }
    
    checkImage("foo.gif", function(){ console.log("good"); }, function(){ console.log("bad"); } );

    checkImage("favicon.ico", function(){ console.log("good"); }, function(){ console.log("bad"); } );

JSFiddle

Community
  • 1
  • 1
epascarello
  • 204,599
  • 20
  • 195
  • 236
  • Hey, cool function! As a side note, this is an interesting way of returning the results, direct into an anonymous function. I would normally do this with a `return` statement like @ajtrichards has in the first part of his answer. – Sablefoste Jan 18 '17 at 20:44
  • Absolutely; but I never really thought about the other way being synchronous. I am coming from a long history of procedural coding, and sometimes miss the "other" way of looking at things... I'll bet I'm not the only one. ;-) – Sablefoste Jan 18 '17 at 22:03
  • 3
    For future googlers having a problem this solution, try moving the img.src definition to immediately after the new Image line. – Gavin Jul 26 '17 at 08:36
  • 1
    This will not help catching 404 errors if image server returns 404 with actual image content, as e.g. Youtube thumbnail service does: https://i3.ytimg.com/vi/vGc4mg5pul4/maxresdefault.jpg – gvlasov Sep 15 '20 at 19:53
  • @gvlasov so if that is the case, you have to do the head request and look at the response. One option of many from a question back in 2013... – epascarello Sep 15 '20 at 20:07
  • Head request won't work because of CORS. I guess the only solution is using YouTube API. – Ilya Levin Apr 20 '21 at 14:28
  • I had to change this code quite a bit to get it to work with my program, however, it's very clever, great job! – Dennis Kozevnikoff Aug 10 '21 at 20:27
69

You can just check if the image loads or not by using the built in events that is provided for all images.

The onload and onerror events will tell you if the image loaded successfully or if an error occured :

var image = new Image();

image.onload = function() {
    // image exists and is loaded
    document.body.appendChild(image);
}
image.onerror = function() {
    // image did not load

    var err = new Image();
    err.src = '/favicon.ico';

    document.body.appendChild(err);
}

image.src = "../imgs/6.jpg";
Benjamin Buch
  • 4,752
  • 7
  • 28
  • 51
adeneo
  • 312,895
  • 29
  • 395
  • 388
  • 2
    The best answer for me, as it works in every case (connexion problem, external server...) +1 – Reign.85 Sep 30 '14 at 17:18
  • 3
    Compared the performance of this answer with the AJAX.get alternative. This answer performs much faster! – Samuel Feb 16 '16 at 19:38
  • I like this solution, anyhow it introduces events in both cases (asynchronous execution), which can cause problems in some situations: I would suggest to append the image in any case and then substitute it only in the case of errors. – Giorgio Tempesta Jan 31 '18 at 11:01
  • @adeno, Does it work when Status Code: 404 Not Found – Mahi Mar 11 '19 at 08:03
  • @Mahi - The status code shouldn't matter, as long as the 404 page doesn't actually return a valid image, it will fail and trigger the `error` handler. – adeneo Mar 21 '19 at 22:39
29

A better and modern approach is to use ES6 Fetch API to check if an image exists or not:

fetch('https://via.placeholder.com/150', { method: 'HEAD' })
    .then(res => {
        if (res.ok) {
            console.log('Image exists.');
        } else {
            console.log('Image does not exist.');
        }
    }).catch(err => console.log('Error:', err));

Make sure you are either making the same-origin requests or CORS is enabled on the server.

attacomsian
  • 2,667
  • 23
  • 24
16

If anyone comes to this page looking to do this in a React-based client, you can do something like the below, which was an answer original provided by Sophia Alpert of the React team here

getInitialState: function(event) {
    return {image: "http://example.com/primary_image.jpg"};
},
handleError: function(event) {
    this.setState({image: "http://example.com/failover_image.jpg"});
},
render: function() {
    return (
        <img onError={this.handleError} src={src} />;
    );
}
j_quelly
  • 1,399
  • 4
  • 16
  • 37
Jordan Bonitatis
  • 1,527
  • 14
  • 12
15

Basicaly a promisified version of @espascarello and @adeneo answers, with a fallback parameter:

const getImageOrFallback = (path, fallback) => {
  return new Promise(resolve => {
    const img = new Image();
    img.src = path;
    img.onload = () => resolve(path);
    img.onerror = () => resolve(fallback);
  });
};

// Usage:

const link = getImageOrFallback(
  'https://www.fillmurray.com/640/360',
  'https://via.placeholder.com/150'
  ).then(result => console.log(result) || result)

Edit march 2021 After a conversation with @hitautodestruct I decided to add a more "canonical" version of the Promise based function. onerror case is now being rejected, but then caught and returning a default value:

function getImageOrFallback(url, fallback) {
  return new Promise((resolve, reject) => {
    const img = new Image()
    img.src = url
    img.onload = () => resolve(url)
    img.onerror = () => {
      reject(`image not found for url ${url}`)
    }
  }).catch(() => {
    return fallback
  })
}

getImageOrFallback("https://google.com", "https://picsum.photos/400/300").then(validUrl => {
  console.log(validUrl)
  document.body.style.backgroundImage = `url(${validUrl})`
})
html, body {
  height: 100%;
  background-repeat: no-repeat;
  background-position: 50% 50%;
  overflow-y: hidden;
}

Note: I may personally like the fetch solution more, but it has a drawback – if your server is configured in a specific way, it can return 200 / 304, even if the file doesn't exist. This, on the other hand, will do the job.

HynekS
  • 2,738
  • 1
  • 19
  • 34
  • 2
    For `fetch`, you can use the `ok` property of the `response` object to check whether the request was successful or not: `fetch(url).then(res => {if(res.ok){ /*exist*/} else {/*not exist*/}});` – attacomsian May 18 '19 at 07:51
  • 1
    That unfortunately does not work for me if I want to check valid background image. `background-image: url('/a/broken/url')` gives me `200` and `ok` (Chrome 74). – HynekS May 20 '19 at 10:22
  • @HynekS I would suggest rejecting the promise in the `onerror` call back instead of `resolve`. `new Promise( (resolve, reject) => { /*...*/ img.onerror = () => reject('Not found') } )` – hitautodestruct Mar 09 '21 at 13:52
  • @hitautodestruct The reason I am always resolving, even in the "error" case, is that I often use this pattern inside `Promise.all()`, where rejecting one item rejects the whole list. Also, I *expect* it to always return *something* (existing image url: hence the functions name). While I am not an FP geek, I like to think about it as of an `Either` monad. – HynekS Mar 10 '21 at 08:03
  • @HynekS You might want to note the use of `Promise.all()` in the answer. IMO if you're answer is "a promisified version..." then it should be written as close as possible to a classic promise, otherwise it may cause confusion for people who are not familiar with promises. Also, You might want to consider [`Promise.allSettled()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled) instead of `Promise.all()` so as to not fail all promises on any `reject`. – hitautodestruct Mar 11 '21 at 09:11
  • @hitautodestruct Point taken, I've added a more 'canonical' version of the function (rejects on `onerror`, but then catches and returns a default value). It should be working inside `Promise.all` as well. Credits to David Walsh (https://davidwalsh.name/javascript-promise-catch). – HynekS Mar 15 '21 at 12:32
6

If you create an image tag and add it to the DOM, either its onload or onerror event should fire. If onerror fires, the image doesn't exist on the server.

Douglas
  • 36,802
  • 9
  • 76
  • 89
5

You may call this JS function to check if file exists on the Server:

function doesFileExist(urlToFile)
{
    var xhr = new XMLHttpRequest();
    xhr.open('HEAD', urlToFile, false);
    xhr.send();

    if (xhr.status == "404") {
        console.log("File doesn't exist");
        return false;
    } else {
        console.log("File exists");
        return true;
    }
}
Ani Menon
  • 27,209
  • 16
  • 105
  • 126
3

You can do this with your axios by setting relative path to the corresponding images folder. I have done this for getting a json file. You can try the same method for an image file, you may refer these examples

If you have already set an axios instance with baseurl as a server in different domain, you will have to use the full path of the static file server where you deploy the web application.

  axios.get('http://localhost:3000/assets/samplepic.png').then((response) => {
            console.log(response)
        }).catch((error) => {
            console.log(error)
        })

If the image is found the response will be 200 and if not, it will be 404.

Also, if the image file is present in assets folder inside src, you can do a require, get the path and do the above call with that path.

var SampleImagePath = require('./assets/samplepic.png');
axios.get(SampleImagePath).then(...)
Rohith Murali
  • 5,551
  • 2
  • 25
  • 26
3

Just Promise function versions of the answers here with true/false return value:

With new Image(); methods (preferred):

async function imageExists(imgUrl) {
    if (!imgUrl) {
        return false;
    }
    return new Promise(res => {
        const image = new Image();
        image.onload = () => res(true);
        image.onerror = () => res(false);
        image.src = imgUrl;
    });
}

// test
(async () => {
  // true
  console.log(await imageExists('https://www.gstatic.com/webp/gallery3/1.png'));
  // false
  console.log(await imageExists('https://www.gstatic.com/webp/gallery3/DOES_NOT_EXIST_THERE.png'));
})()

With XMLHttpRequest (less data, but maybe makes cors problems):

async function fileExists(fileUrl) {
    if (!fileUrl) {
        return false;
    }
    return new Promise(res => {
        const http = new XMLHttpRequest();
        http.open('HEAD', fileUrl, true);
        http.send();
        http.onload = () => {
            res(http.status != 404);
        };
        http.onerror = () => {
            res(false);
        };
    });
}

// test
(async () => {
  // true
  console.log(await fileExists('https://www.gstatic.com/webp/gallery3/1.png'));
  // false
  console.log(await fileExists('https://www.gstatic.com/webp/gallery3/DOES_NOT_EXIST_THERE.png'));
})()

With fetch (modern browsers, less data, maybe CORS problems)

async function fileExists(fileUrl) {
    if (!fileUrl) {
        return false;
    }
    const res = await fetch(fileUrl, {
      method: 'HEAD',
    });
    return !!res.ok;
}

// test
(async () => {
  // false
  console.log(await fileExists('https://www.gstatic.com/webp/gallery3/1.png'));
  // false
  console.log(await fileExists('https://www.gstatic.com/webp/gallery3/DOES_NOT_EXIST_THERE.png'));
  

})()
TypeScript versions:
// with `new Image();` method
async function imageExists(imgUrl: string | null | undefined): Promise<boolean> {
  if (!imgUrl) {
    return false;
  }

  return new Promise(res => {
    const image = new Image();
    image.onload = () => res(true);
    image.onerror = () => res(false);
    image.src = imgUrl;
  });
}

// with `XMLHttpRequest` method
async function fileExists(fileUrl: string | null | undefined): Promise<boolean> {
  if (!fileUrl) {
    return false;
  }

  return new Promise(res => {
    const http = new XMLHttpRequest();

    http.open('HEAD', fileUrl, false);
    http.send();
    http.onload = () => {
        res(http.status != 404);
    };
    http.onerror = () => {
        res(false);
    };

  });
}

// with `fetch` method
async function fileExists(fileUrl: string | null | undefined): Promise<boolean>  {
  if (!fileUrl) {
    return false;
  }
  const res = await fetch(fileUrl, {
    method: 'HEAD',
  });

  return !!res.ok;
}
ya_dimon
  • 3,483
  • 3
  • 31
  • 42
2

I was having some struggles with displaying an image of a user via JS: If the user image was misssing - it gave an error.

It turns out you can do the following in the html to display an specific image when the loading of an image faills

<img src="img/path/image.png" onerror="javascript:this.src='img/path/no-image.png'">

Just wanted to share it... Perhaps this can save some time for you!

guruguldmand
  • 179
  • 1
  • 1
  • 10
1

If you are using React try this custom Image component:

import React, { useRef } from 'react';
import PropTypes from 'prop-types';

import defaultErrorImage from 'assets/images/default-placeholder-image.png';

const Image = ({ src, alt, className, onErrorImage }) => {
  const imageEl = useRef(null);
  return (
    <img
      src={src}
      alt={alt}
      className={className}
      onError={() => {
        imageEl.current.src = onErrorImage;
      }}
      ref={imageEl}
    />
  );
};

Image.defaultProps = {
  onErrorImage: defaultErrorImage,
};

Image.propTypes = {
  src: PropTypes.string.isRequired,
  alt: PropTypes.string.isRequired,
  className: PropTypes.string.isRequired,
  onErrorImage: PropTypes.string,
};

export default Image;
1

This works fine if you want to know if an image is in the folder

function checkImage(var, extension){
  var image = new Image();
  var url_image = './folder/' + var + '.' + extension;
  image.src = url_image;
  return image.width !== 0;
}
Flozii
  • 11
  • 2
  • This question probably aged away (almost 8 years old). You can also simplify that last part to `return image.width !== 0` – F. Müller Sep 10 '21 at 18:19
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-ask). – Community Sep 10 '21 at 18:59
0
function checkImage(var){
  var image = new Image();
  var url_image = './folder/' + variable + '.jpg';
  image.src = url_image;
  if (image.width == 0) {
    return false;
  } else {
    return true;
  }
}
Flozii
  • 11
  • 2
0

This is code work for me. I found when you test several images in an array and you want to immediately return, it will not work.

You need to give browser some time to load the image, otherwise it will not working.

Solutions works fine:

let images = ["invalid.jpg", "invalid2.jpg", "https://upload.wikimedia.org/wikipedia/en/thumb/8/80/Wikipedia-logo-v2.svg/1200px-Wikipedia-logo-v2.svg.png"]
let workedimages = images.slice()
images.forEach((item, index) => {
  let img = new Image()
  img.src = item
  img.onerror = () => workedimages.splice(workedimages.indexOf(item), 1)
  if (index == images.length - 1) {
    img.onload = () =>
      console.log(workedimages)
  }
})
James
  • 2,732
  • 2
  • 5
  • 28
0

I've found my own solution : fetch the image and check the response status

var path = "../folder/image.jpg";

fetch(path)
  .then(function(response) {
      if(response.status != 200){
            console.log("The image exists");
        }else{
            console.log("The image doesn't exist");
         }
     })
-2

Simple effective, one line of code.

var x = new XMLHttpRequest(); x.open("get", "your_url.com/image.ext or /image.png or image.jpg", true);x.onreadystatechange = function () { if (this.readyState == 4 && this.status == 200) {alert('exist');}else{alert('does not exist'};}; x.send();
Devmyselz
  • 346
  • 3
  • 13
-3

You can refer this link for check if a image file exists with JavaScript.

checkImageExist.js:

    var image = new Image();
    var url_image = './ImageFolder/' + variable + '.jpg';
    image.src = url_image;
    if (image.width == 0) {
       return `<img src='./ImageFolder/defaultImage.jpg'>`;
    } else {
       return `<img src='./ImageFolder/`+variable+`.jpg'`;
    } } ```
Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • 2
    I just tested this. **It doesn't work**. It always returns the default image. (Probably because there is no time for the browser to make the HTTP request and load the image before you try to test the width of it). – Quentin Oct 25 '19 at 06:37