Waiting for image to load in JavaScript
Solution 1
var img = new Image();
img.onload = function() { alert("Height: " + this.height); }
img.src = "http://path/to/image.jpg";
Note that it's important to do it in the order above: First attach the handler, then set the src
. If you do it the other way around, and the image is in cache, you may miss the event. JavaScript is run on a single thread in browsers (unless you're using web workers), but browsers are not single-threaded. It's perfectly valid for the browser to see the src
, identify the resource is available, load it, trigger the event, look at the element to see if it has any handlers that need to be queued for callback, not see any, and complete the event processing, all between the src
line and the line attaching the handler. (The callbacks wouldn't happen between the lines if they were registered, they'd wait in the queue, but if there aren't any, the event isn't required to wait.)
Solution 2
If you use jQuery, you can use its load event.
Have a look at the example:
$('img.userIcon').load(function(){
if($(this).height() > 100) {
$(this).addClass('bigImg');
}
});
Solution 3
The accepted answer is outdated but does show the basic Image#onload
callback approach. Nowadays, you'll likely want to promisify the image load to avoid callback hell.
This answer is a good shot at promisifying the image onload handler, but is missing some key points as my comment indicates.
Here's another promisification of Image
that is a bit more general. Rejecting in the onerror
handler and passing the actual image object into the resolver are important to make the function minimally reusable.
Improvements might include additional parameters (such as crossOrigin
, for example). A settings
object or providing an Image
as a parameter is another approach to generalize the function (setting src
fires the request, so that should go last after handlers have been added).
const loadImage = src =>
new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = reject;
img.src = src;
})
;
loadImage("http://placekitten.com/90/100").then(image =>
console.log(image, `\nloaded? ${image.complete}`)
);
With the above function, Promise.all
can be used to load a batch of images in parallel (Promise.allSettled
is useful if you want to keep going even if some images don't load).
const loadImage = src =>
new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = reject;
img.src = src;
})
;
const imageUrls = [
"http://placekitten.com/85/150",
"http://placekitten.com/85/130",
"http://placekitten.com/85/110",
];
Promise.all(imageUrls.map(loadImage)).then(images => {
const canvas = document.createElement("canvas");
document.body.appendChild(canvas);
const ctx = canvas.getContext("2d");
images.forEach((image, i) =>
ctx.drawImage(image, i * 90, 0, image.width, image.height)
);
});
Solution 4
just wrap your image onload in a function with a promise and then call it with await.
async drawImg(ctx, image){
return new Promise(resolve => {
image.onload = function () {
ctx.drawImage(image, 10, 10, 200, 180);
resolve('resolved');
}
});
}
it should work just fine
Solution 5
How about the window load event?
window.addEventListener('load', (event) => {
//do stuff with images
});
or
window.onload = (event) => {
//do stuff with images
};
https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event
This worked for me where I needed the browser to calculate the size of the images before running a layout script.
Related videos on Youtube
Jeenyus
Updated on May 14, 2022Comments
-
Jeenyus almost 2 years
I'm making an Ajax call which returns me some info including an image path.
I prepare all this information in my HTML which will be displayed as a kind of popup. I just toggle the visibility of by popup div from hidden to visible.
To set the position of my popup div, I have to calculate depending on the height of the image. So, I have to wait for the image to load to know its dimension before setting position and switching visibility to visible.
I tried tricks with recursion, setTimeout, complete img property, while loop... without success.
So, how can I do this? Maybe I should return dimensions in my Ajax call.
-
Otto Allmendinger about 14 yearswhy doesn't it work with the
Image.complete
property?
-
-
Andy E about 14 years-1: no mention of jQuery in the question, so an answer like this can be quite confusing.
-
Marco Demaio about 14 yearsGrat! BTW: i'm quite ignorant on the AJAX subject, but just in case an image got with AJAX is cached in the same way of an image written dierctly into HTML code, you could eventually add this in order to avoid browser's image caching (obviously only if you need it): img.src="path/to/image.jpg"+"?refresh="+new Date().getTime();
-
Josh Stodola about 14 years@Marco Or set
cache: false
on the XHR :) Although I don't think it's relevant here because the AJAX call is returning a URL to the image, not the image itself. But yes I suppose he could still use a random query string value to make sure no user-agent caching occurs. -
Rich O'Kelly over 10 yearsPlease also note the following caveats with the load method when used with images (taken from api.jquery.com/load-event): > It doesn't work consistently nor reliably cross-browser > It doesn't fire correctly in WebKit if the image src is set to the same src as before > It doesn't correctly bubble up the DOM tree > Can cease to fire for images that already live in the browser's cache
-
IQAndreas about 10 yearsCan you add an event listener as well, or is replacing
onload
the way? -
T.J. Crowder over 8 years@IQAndreas: You could use
img.addEventListener("load", ...)
, yes. (Orimg.attachEvent("onload", ...)
on old IE). -
Ali Sheikhpour over 4 yearsDoes it matter if I change the order of second and third line?
-
Arkady about 4 yearsIt doesn't actually answer the question: how to wait for image to load (obviously in current thread).
-
ggorlen about 3 yearsThe
async
keyword here is unnecessary--returning a promise is enough for the caller toawait
it. It's also a good idea to promisify the onerror handler withreject()
so the caller can catch the error if the load fails. Last suggestion: you could pass the image object itself toresolve(this)
so that the caller can draw the image or do what they want with it. -
Joseph about 3 yearsThis doesn't quite seem to answer the question, as there are many times that an image can be loaded after the page itself loads, including this example. The onload event on window does wait for images to be loaded, but only for the initial page load. In the context of this question, the onload event should be tied directly to the image element that is being loaded instead.
-
gyozo kudor almost 3 yearsCan I do this without creating an image element from Javascript?
-
algiogia over 2 yearsDoesn't work for me. The onload function is executed even before setting img.src.
-
Rylan Schaeffer about 2 yearsThis doesn't work for me either. Can you please update your answer?