I have this function in JS that preloads images:
// http://stackoverflow.com/questions/3646036/javascript-preloading-images
var preloaded_images = [];
function preload() {
for (i = 0; i < arguments.length; i++) {
preloaded_images[i] = new Image();
preloaded_images[i].src = preload.arguments[i];
}
}
However, some images I try to preload throw 404 errors. How can I detect a 404 within this function, without trying to add the image to the DOM?
You could attach the onerror eventHandler:
...
preloaded_images[i].onerror = function() {
// the image couldn't be loaded..
}
...
And if you want to know it was loaded successful, you would do:
...
preloaded_images[i].onload = function() {
// the image was loaded successful..
}
...
Fiddle
I've searched high and low for a solution to this problem, extremely grateful to anyone who can shed some light.
Below is a simplified version of a function used to preload 25 images. It works fantastically well in IE9-10 and in Chrome.
In IE8 it gets partway through loading the images (e.g. 10/25) then just stops. If I then refresh the browser it will continue to load images, taking ~3 refreshes to complete. This should not be necessary!
On the odd occasion it does succeed in loading all images in one go. I tried to avoid using .load() as I've read it can be problematic in IE yet here I am just the same! I also tried using different images to rule out the image format as the cause.
I'm looking for either a fix to the below code or a better solution if someone has one.
Many thanks.
function loadAllImages() {
var imgArray = [ //image SRCs stored in array
'imgsrc01.jpg',
'imgsrc02.jpg',
'imgsrc03.jpg',
...
'imgsrc25.jpg'];
var noFinalImg = imgArray.length - 1;
var i = -1;
var waitTime = 10000;
if (imgArray.length === 0) {
return;
} else {
loadImage();
};
function loadImage() {
i++;
var url = imgArray[i];
var img = new Image();
var timer;
img.src = url;
img.id = "thumb" + i;
// image loaded
if (img.complete || img.readyState === 4) {
//Call image loaded function
console.log(i + "/" + noFinalImg);
//equivalent to loop next
if (i !== noFinalImg) {
loadImage();
};
// image not loaded
} else {
// handle 404 using setTimeout set at waitTime
timer = setTimeout(function () {
if (i !== noFinalImg) {
loadImage();
};
$(img).unbind('error load onreadystate');
}, waitTime);
$(img).bind('error load onreadystatechange', function (e) {
clearTimeout(timer);
if (e.type !== 'error') {
//Call image loaded function
console.log(i + "/" + noFinalImg);
};
if (i !== noFinalImg) {
loadImage();
};
});
};
};
};
I'm trying to load my images and fade in. Its working. But lets suppose that I have 4 images. Right now, my script its working by loading the last image, not the first. How can I make my js load the first image, and just start loading the second after the first has been loaded?
Here's my code:
$(function(){
$("a").click(function(){
$("#load").load('load.html', function() {
$('#load img').hide();
alert($("#load img").length);
$('#load img').each( function(){
$(this).on('load', function () {
$(this).fadeIn();
});
});
});
return false;
});
});
See http://jsfiddle.net/5uNGR/15/
Try something where you are not trying to perform a fadeIn on each image as they load, but test the ok-ness of the next image in your animation queue each time ANY load event happens, then on the animation callback, see if the next one is ready. Here is a script that should work.
BTW, see http://www.sajithmr.me/javascript-check-an-image-is-loaded-or-not for more on image readiness testing.
$(function () {
// util fn to test if image loaded properly
var isImgLoadOk = function (img) {
if (!img.complete) { return false; }
if (typeof img.naturalWidth != "undefined" && img.naturalWidth == 0) {
return false;
}
return true;
};
$("a").on('click', function () {
$("#load").load('load.html', function () {
var imgs = $('#load img').hide(), //create image array and hide (chaining)
animIndex = 0, //position in the animation queue
isFading = false; //track state of whether an animation is in prog
// this is a load handler AND is called in the fadeIn callback if
// not at last image in the collection
var fadeNextImg = function () {
// make sure a load event didn't happen in the middle of an animation
if (isFading) return;
// last image in animation queue?
var isLast = animIndex == imgs.length - 1;
// get the raw image out of the collection and test if it is loaded happily
var targetImage = imgs[animIndex];
if (isImgLoadOk(targetImage)) {
// jQuery-up the htmlImage
targetImage = $(targetImage);
// increment the queue
animIndex++;
// set animation state - this will ignore load events
isFading = true;
// fade in the img
targetImage.fadeIn('slow', function () {
isFading = false;
// test to see if next image is ready to load by
// recursively calling the parent fn
if (!isLast) fadeNextImg();
});
}
};
imgs.on('load', fadeNextImg);
});
return false;
});
});
Ron's solution is a little over-engineered IMO. If your intention is indeed to load all of the images before the animation starts, then you could do something similar to the following:
$(function(){
$("a").click(function(){
$("#load").load('load.html', function() {
$('#load img').hide(); // I would recommend using css to hide the image instead
alert($("#load img").length);
$("#load img").each(function(i, image) {
setTimeout(function() { // For each image, set increasingly large timeout before fadeIn
$(this).fadeIn();
}, 2000 * i);
});
});
return false;
});
});
i am still new to all the Javascript stuffs and i have to be honest that i have not yet experimented anything concerning my question.
I would like to know if there is a way or a plugin with jQuery to preloaded multiples images and call a function when the images are loaded?
You can use the load event for images, but they have a number of cross browser issues (it depends on what platforms you're targeting).
var allImgs = $("#container img").filter(function() { return ! this.complete; });
var allImgsLength = allImgs.length;
allImgs.on("load", function() {
if (--allImgsLength) {
// Images have loaded.
}
});
If you don't mind including a plugin, there is waitForImages, (disclaimer: written by me) which handles this relatively nicely. :)
You'd use it like...
$("#container").waitForImages(function() {
// Images have loaded.
});
If you don't want to use jQuery at all, you can adapt the first example. If you're only targeting modern browsers...
var allImgs = [].filter.call(document.querySelectorAll("#container img"),
function(img) {
return ! img.complete;
});
var allImgsLength = allImgs.length;
[].forEach.call(allImgs, function(img) {
img.addEventListener(function() {
if (--allImgsLength) {
// Images have loaded.
}
});
});
If you had to support old browsers...
var allImgs = document.getElementById("container").getElementsByTagName("img");
var allImgsLength = allImgs.length;
var i;
var eventCallback = function() {
if (--allImgsLength) {
// Images have loaded.
}
};
for (i = 0; i < allImgsLength; i++) {
if (allImgs[i].complete) {
allImgsLength--;
}
if (allImgs[i].addEventListener) {
allImgs[i].addEventListener("load", eventCallback);
} elseif (allImgs[i].attachEvent) {
allImgs[i].attachEvent("onload", eventCallback);
} else {
allImgs[i].onload = eventCallback;
}
}
I want to know when an image has finished loading. Is there a way to do it with a callback?
If not, is there a way to do it at all?
.complete + callback
This is a standards compliant method without extra dependencies, and waits no longer than necessary:
var img = document.querySelector('img')
function loaded() {
alert('loaded')
}
if (img.complete) {
loaded()
} else {
img.addEventListener('load', loaded)
img.addEventListener('error', function() {
alert('error')
})
}
Source: http://www.html5rocks.com/en/tutorials/es6/promises/
Image.onload() will often work.
To use it, you'll need to be sure to bind the event handler before you set the src attribute.
Related Links:
Mozilla on Image.onload()
Example Usage:
window.onload = function () {
var logo = document.getElementById('sologo');
logo.onload = function () {
alert ("The image has loaded!");
};
setTimeout(function(){
logo.src = 'https://edmullen.net/test/rc.jpg';
}, 5000);
};
<html>
<head>
<title>Image onload()</title>
</head>
<body>
<img src="#" alt="This image is going to load" id="sologo"/>
<script type="text/javascript">
</script>
</body>
</html>
You can use the .complete property of the Javascript image class.
I have an application where I store a number of Image objects in an array, that will be dynamically added to the screen, and as they're loading I write updates to another div on the page. Here's a code snippet:
var gAllImages = [];
function makeThumbDivs(thumbnailsBegin, thumbnailsEnd)
{
gAllImages = [];
for (var i = thumbnailsBegin; i < thumbnailsEnd; i++)
{
var theImage = new Image();
theImage.src = "thumbs/" + getFilename(globals.gAllPageGUIDs[i]);
gAllImages.push(theImage);
setTimeout('checkForAllImagesLoaded()', 5);
window.status="Creating thumbnail "+(i+1)+" of " + thumbnailsEnd;
// make a new div containing that image
makeASingleThumbDiv(globals.gAllPageGUIDs[i]);
}
}
function checkForAllImagesLoaded()
{
for (var i = 0; i < gAllImages.length; i++) {
if (!gAllImages[i].complete) {
var percentage = i * 100.0 / (gAllImages.length);
percentage = percentage.toFixed(0).toString() + ' %';
userMessagesController.setMessage("loading... " + percentage);
setTimeout('checkForAllImagesLoaded()', 20);
return;
}
}
userMessagesController.setMessage(globals.defaultTitle);
}
Life is too short for jquery.
function waitForImageToLoad(imageElement){
return new Promise(resolve=>{imageElement.onload = resolve})
}
var myImage = document.getElementById('myImage');
var newImageSrc = "https://pmchollywoodlife.files.wordpress.com/2011/12/justin-bieber-bio-photo1.jpg?w=620"
myImage.src = newImageSrc;
waitForImageToLoad(myImage).then(()=>{
// Image have loaded.
console.log('Loaded lol')
});
<img id="myImage" src="">
You could use the load()-event in jQuery but it won't always fire if the image is loaded from the browser cache. This plugin https://github.com/peol/jquery.imgloaded/raw/master/ahpi.imgload.js can be used to remedy that problem.
If the goal is to style the img after browser has rendered image, you should:
const img = new Image();
img.src = 'path/to/img.jpg';
img.decode().then(() => {
/* set styles */
/* add img to DOM */
});
because the browser first loads the compressed version of image, then decodes it, finally paints it. since there is no event for paint you should run your logic after browser has decoded the img tag.
Here is jQuery equivalent:
var $img = $('img');
if ($img.length > 0 && !$img.get(0).complete) {
$img.on('load', triggerAction);
}
function triggerAction() {
alert('img has been loaded');
}
Not suitable for 2008 when the question was asked, but these days this works well for me:
async function newImageSrc(src) {
// Get a reference to the image in whatever way suits.
let image = document.getElementById('image-id');
// Update the source.
img.src = src;
// Wait for it to load.
await new Promise((resolve) => { image.onload = resolve; });
// Done!
console.log('image loaded! do something...');
}
these functions will solve the problem, you need to implement the DrawThumbnails function and have a global variable to store the images. I love to get this to work with a class object that has the ThumbnailImageArray as a member variable, but am struggling!
called as in addThumbnailImages(10);
var ThumbnailImageArray = [];
function addThumbnailImages(MaxNumberOfImages)
{
var imgs = [];
for (var i=1; i<MaxNumberOfImages; i++)
{
imgs.push(i+".jpeg");
}
preloadimages(imgs).done(function (images){
var c=0;
for(var i=0; i<images.length; i++)
{
if(images[i].width >0)
{
if(c != i)
images[c] = images[i];
c++;
}
}
images.length = c;
DrawThumbnails();
});
}
function preloadimages(arr)
{
var loadedimages=0
var postaction=function(){}
var arr=(typeof arr!="object")? [arr] : arr
function imageloadpost()
{
loadedimages++;
if (loadedimages==arr.length)
{
postaction(ThumbnailImageArray); //call postaction and pass in newimages array as parameter
}
};
for (var i=0; i<arr.length; i++)
{
ThumbnailImageArray[i]=new Image();
ThumbnailImageArray[i].src=arr[i];
ThumbnailImageArray[i].onload=function(){ imageloadpost();};
ThumbnailImageArray[i].onerror=function(){ imageloadpost();};
}
//return blank object with done() method
//remember user defined callback functions to be called when images load
return { done:function(f){ postaction=f || postaction } };
}
This worked for me:
// Usage
let img = await image_on_load(parent_element_to_put_img, image_url);
img.hidden = true;
// Functions
async function image_on_load(parent, url) {
let img = element(parent, 'img');
img.src = url;
await new Promise((resolve, reject) => {
element_on(img, 'load', () => {
resolve();
});
element_on(img, 'error', () => {
reject();
});
});
return img;
}
function element(parent, tag_name, text = '') {
let result = document.createElement(tag_name);
element_child_append(parent, result);
element_html_inner(result, text);
return result;
}
function element_child_append(parent, result) {
parent.appendChild(result);
}
function element_html_inner(result, text) {
result.innerHTML = text;
}
function element_on(e, event, on_event) {
e.addEventListener(event, async () => {
await on_event();
});
}
If you are using React.js, you could do this:
render() {
// ...
<img
onLoad={() => this.onImgLoad({ item })}
onError={() => this.onImgLoad({ item })}
src={item.src} key={item.key}
ref={item.key} />
// ...
}
Where:
- onLoad (...) now will called with something like this:
{ src: "https://......png", key:"1" }
you can use this as "key" to know which images is loaded correctly and which not.
- onError(...) it is the same but for errors.
- the object "item" is something like this { key:"..", src:".."}
you can use to store the images' URL and key in order to use in a list of images.