144

I want to load external images on my page asynchronously using jQuery and I have tried the following:

$.ajax({ 
   url: "http://somedomain.com/image.jpg", 
   timeout:5000,
   success: function() {

   },
   error: function(r,x) {

   }
});

But it always returns error, is it even possible to load image like this?

I tried to use .load method and it works but I have no idea how I can set timeout if the image is not available (404). How can I do this?

Gras Double
  • 14,028
  • 7
  • 52
  • 50
Arief
  • 5,957
  • 7
  • 34
  • 41
  • This works for me: https://stackoverflow.com/questions/6150289/how-to-convert-image-into-base64-string-using-javascript – MrRhoads Oct 11 '17 at 02:07

10 Answers10

201

No need for ajax. You can create a new image element, set its source attribute and place it somewhere in the document once it has finished loading:

var img = $("<img />").attr('src', 'http://somedomain.com/image.jpg')
    .on('load', function() {
        if (!this.complete || typeof this.naturalWidth == "undefined" || this.naturalWidth == 0) {
            alert('broken image!');
        } else {
            $("#something").append(img);
        }
    });
Mark Amery
  • 110,735
  • 57
  • 354
  • 402
karim79
  • 326,960
  • 63
  • 404
  • 402
  • 20
    what to do with the timeout and 404? – Arief Nov 26 '10 at 11:56
  • @Arief - Please see my edit. You can test the image's complete property, and natural width. – karim79 Nov 26 '10 at 12:00
  • 1
    how to set timeout with this? I tried this method but somehow the page still waits for the image to load. – Arief Dec 06 '10 at 09:40
  • 7
    If you check your browser's timeline, for example, Google Chrome's dev tools timeline, you will see that creating any DOM element (whether or not you attach it to the DOM is irrelevant apparently) and then setting its source adds it to the current document's load list - so the page will NOT finish "loading" until that created element is loaded. Your solution is actually not an asyncrhonous event in the sense that window.load() will not fire until the image has loaded, possibly deferring certain `paint` or `layout` operations, and certainly delaying any `onload` event dependencies. – Tom Auger Nov 16 '11 at 21:20
  • 2
    @TomAuger : So how can we make it really asynchronous? I just tested the code with load() and it is NOT asynchronous. – basZero Mar 05 '12 at 09:28
  • 1
    If you load it on some different event then it is Asynchronous, surely. I've used similar code on my site for a portfolio, when a user clicks on a project, the images are loaded into the appropriate divs etc (= async). – Alex Jun 03 '12 at 22:53
  • 1
    it doesn't work in IE8, anybody knows why ?? i have "broken image" alert – gidzior Oct 05 '12 at 13:54
  • DONT USER Load, you cant cancel it after it is called – PUG Feb 05 '13 at 06:35
  • @karim, The advantage of Ajax is that we can abort the request it anytime we want. – Pacerier May 24 '13 at 22:40
  • 1
    Your solution works perfectly, but why does it? I didn't find any documentation that said you can call `load` without any URL – Yamcha Jul 09 '13 at 14:56
  • 2
    @gidzior It doesn't work in IE8 because you can't set the SRC attribute in IE8 using jquery. refer here: http://stackoverflow.com/questions/12107487/internet-explore-8-wont-change-image-src-with-attr – Rich Jul 14 '13 at 08:51
  • didn't he want it through ajax though? i want to track progress, and it can't be done this way – Atharva Johri Jul 29 '13 at 13:39
  • I think what most people want to know, is how do you do this in jQuery or plain JS to understand the underlying differences on how different data is processed. My curiosity originated from AJAX = Asynchronous JavaScript and XML. So what if I am interested in a non XML asynch request? What if I want an image? And so on... – jj_ Jul 25 '14 at 12:06
  • @Arief it's been a while since you asked the question, but did you manage to solve the timeout problem? I'm having the exact same problem. – mila Jul 29 '15 at 13:38
  • 1
    @Yamcha here's the documentation on calling `.load()` without passing a URL as the first argument: http://api.jquery.com/load-event/. The docs note that *"The Ajax module also has a method named `.load()`. Which one is fired depends on the set of arguments passed."* Note also that (presumably because the existence of two distinct functions called `.load()` confused people - like you!) using `.load()` just to bind a handler is deprecated in favour of `.on('load', handler)`. I'm editing the answer to use the non-deprecated form. – Mark Amery Aug 29 '15 at 12:28
78

IF YOU REALLY NEED TO USE AJAX...

I came accross usecases where the onload handlers were not the right choice. In my case when printing via javascript. So there are actually two options to use AJAX style for this:

Solution 1

Use Base64 image data and a REST image service. If you have your own webservice, you can add a JSP/PHP REST script that offers images in Base64 encoding. Now how is that useful? I came across a cool new syntax for image encoding:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhE..."/>

So you can load the Image Base64 data using Ajax and then on completion you build the Base64 data string to the image! Great fun :). I recommend to use this site http://www.freeformatter.com/base64-encoder.html for image encoding.

$.ajax({ 
    url : 'BASE64_IMAGE_REST_URL', 
    processData : false,
}).always(function(b64data){
    $("#IMAGE_ID").attr("src", "data:image/png;base64,"+b64data);
});

Solution2:

Trick the browser to use its cache. This gives you a nice fadeIn() when the resource is in the browsers cache:

var url = 'IMAGE_URL';
$.ajax({ 
    url : url, 
    cache: true,
    processData : false,
}).always(function(){
    $("#IMAGE_ID").attr("src", url).fadeIn();
});   

However, both methods have its drawbacks: The first one only works on modern browsers. The second one has performance glitches and relies on assumption how the cache will be used.

cheers, will

mschmoock
  • 17,114
  • 5
  • 30
  • 32
  • 1
    If the current state of browser support is acceptable to you (http://caniuse.com/#search=Blob), you can use [Blobs](https://developer.mozilla.org/en-US/docs/Web/API/Blob) instead of data URIs. This 'feels' less hacky than using base64-encoded data URIs and is also less wasteful of memory (since base64 is not a memory-efficient format), although the latter probably doesn't matter most of the time in the real world. – Mark Amery Aug 29 '15 at 12:32
12

Using jQuery you may simply change the "src" attribute to "data-src". The image won't be loaded. But the location is stored with the tag. Which I like.

<img class="loadlater" data-src="path/to/image.ext"/>

A Simple piece of jQuery copies data-src to src, which will start loading the image when you need it. In my case when the page has finished loading.

$(document).ready(function(){
    $(".loadlater").each(function(index, element){
        $(element).attr("src", $(element).attr("data-src"));
    });
});

I bet the jQuery code could be abbreviated, but it is understandable this way.

htho
  • 947
  • 8
  • 22
  • 4
    Tip: if you're using the `data-` tags, it's a fair bit easier to access them via `$(element).data('src')` instead of `$(element).attr('data-src')` – Maxim Kumpan Jun 28 '17 at 08:36
  • Actually today I would not use jQuery anymore. But thats a question of personal taste, and depends on the scale of the website you are building. But the hot topic of the time is "Progressive Images", maybe that is something to look in to. https://www.smashingmagazine.com/2018/02/progressive-image-loading-user-perceived-performance/ – htho Feb 10 '18 at 15:02
8
$(<img />).attr('src','http://somedomain.com/image.jpg');

Should be better than ajax because if its a gallery and you are looping through a list of pics, if the image is already in cache, it wont send another request to server. It will request in the case of jQuery/ajax and return a HTTP 304 (Not modified) and then use original image from cache if its already there. The above method reduces an empty request to server after the first loop of images in the gallery.

Jaseem
  • 1,938
  • 6
  • 26
  • 33
4

You can use a Deferred objects for ASYNC loading.

function load_img_async(source) {
    return $.Deferred (function (task) {
        var image = new Image();
        image.onload = function () {task.resolve(image);}
        image.onerror = function () {task.reject();}
        image.src=source;
    }).promise();
}

$.when(load_img_async(IMAGE_URL)).done(function (image) {
    $(#id).empty().append(image);
});

Please pay attention: image.onload must be before image.src to prevent problems with cache.

phpcoding
  • 63
  • 6
3

This works too ..

var image = new Image();
image.src = 'image url';
image.onload = function(e){
  // functionalities on load
}
$("#img-container").append(image);
Basilin Joe
  • 552
  • 9
  • 22
3

If you just want to set the source of the image you can use this.

$("img").attr('src','http://somedomain.com/image.jpg');
Alexis Tyler
  • 1,515
  • 6
  • 26
  • 44
slobodan
  • 209
  • 1
  • 4
2

AFAIK you would have to do a .load() function here as apposed to the .ajax(), but you could use jQuery setTimeout to keep it live (ish)

<script>
 $(document).ready(function() {
 $.ajaxSetup({
    cache: false
});
 $("#placeholder").load("PATH TO IMAGE");
   var refreshId = setInterval(function() {
      $("#placeholder").load("PATH TO IMAGE");
   }, 500);
});
</script>
benhowdle89
  • 34,076
  • 63
  • 192
  • 314
  • 2
    sorry i slightly misunderstood your Q, i thought you were loading images that were changing or something (hence the ajax bit) – benhowdle89 Nov 26 '10 at 11:56
2

use .load to load your image. to test if you get an error ( let's say 404 ) you can do the following:

$("#img_id").error(function(){
  //$(this).hide();
  //alert("img not loaded");
  //some action you whant here
});

careful - .error() event will not trigger when the src attribute is empty for an image.

Community
  • 1
  • 1
Poelinca Dorin
  • 9,032
  • 2
  • 34
  • 41
0

$(function () {

    if ($('#hdnFromGLMS')[0].value == 'MB9262') {
        $('.clr').append('<img src="~/Images/CDAB_london.jpg">');
    }
    else
    {
        $('.clr').css("display", "none");
        $('#imgIreland').css("display", "block");
        $('.clrIrland').append('<img src="~/Images/Ireland-v1.jpg">');
    }
});