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)
);
});