Preloading Images: Problem in IE only - javascript

The following Code Works in every browser accept every version of IE, can someone please help! There seems to be a problem with the cat.onload method....I have done so many tests and am at a loss...any help would be appreciated
Thanks!
var bannerCount = 0;
var bannerImgsArr = new Array();
bannerImgsArr[0] ='image1.jpg';
bannerImgsArr[1] ='image2.jpg';
bannerImgsArr[2] ='image3.jpg';
bannerImgsArr[3] ='image4.jpg';
$(document).ready(function() {
preloadBannerImages();
});
function preloadBannerImages(){
//create new image object
var cat = new Image();
//give Image src attribute the image file name
cat.src =bannerImgsArr[bannerCount];
//if the counter represents the last image in the current gallery enter here:
if(bannerCount == 3){
//When the image has been loaded the following function is exicuted
cat.onload = function() {
//Removes the LOADING message hard coded into the html page;
document.getElementById("bigbox").removeChild(document.getElementById("loading"));
}
}else{
//when current image is finished loading increments the img index and
//calls the loading function again for the next image in the gallery
bannerCount++;
cat.onload =preloadBannerImages;
}
}

You are defining the onload handler for the image after setting the src property. Do the one before the other.
If that doesn't solve your problem, you really need to elaborate what exactly doesn't work.

Don't rely on the onload-event of images, it may not fire if the image was loaded before and comes from the cache

[edit]
The function most likely ends and calls itself again before the image is downloaded, so the image isn't cached. Load the images into a persistent store (e.g. array) that hangs around until they are all downlaoded and cached.
[/edit]
You don't have to wait for the DOM to be ready to load images:
var bannerCount = 0;
var bannerImgsArr = ['image1.jpg','image2.jpg','image3.jpg','image4.jpg'];
var imageArray = [];
for (var i=0, iLen=bannerImgsArr.length; i<iLen; i++) {
imageArray[i] = new Image();
imageArray[i].src = bannerImgsArr[i];
}
Now when the DOM is ready, you can use one of the preloaded images.
...
cat.src = imageArr[bannerCount].src;
...

Related

For loop should stop when image is not available in the directory - javascript

My requirement is that, to showcase images available in the directory to the browser view. Using javascript. For that, i have named all images with a same prefix and changed the number to the each image at the end.as shown below.
Folder
gal-img-1.jpg
gal-img-2.jpg
gal-img-3.jpg
gal-img-4.jpg
...
now the code i written something like below.
for(j=1;j<=10;j++){
var objImg = new Image();
var imgSrc = '/assets/images/work/gal-img-'+j+'.jpg'
objImg.src = imgSrc;
objImg.onerror = function (){
j = 11;
console.log("done")
}
}
Now, when i check console, i can see the loop is not stopping when there is no image as 'gal-img-5.jpg'. i see 404 not found error for 5,6,7,8,9,10. after these errors i see "done"(console.log).
Here i want is when there is no image in the directory the for loop needs to stop.
Can someone help me on this.
You can use a bit of recursion using Jaromanda X's mentioned onload method.
function loadImages(i) {
objImg = new Image();
objImg.src = `/assets/images/work/gal-img-${i}.jpg`;
objImg.onload = function () {
if (i < 11) loadImages(++i); // Always have an exit condition with recursion
}
}
// You need to call loadImages(0)
The above would show an error message for the file not found and will not try to load more images.

Why are my images holding up the page load, and how can I defer it/ make it asynchronous or lazy?

I've scouted many forums and blogs and questions and sites and whatnot but cannot seem to find a solution that works for me - I am trying to load images using pure javascript without halting the rest of the page to load, and without relying on third party libraries.
On the site I work on, there may be between 0 - 30 images that may load, of different resolutions, and as you may imagine, might slow down performance to a halt on slower connections (which is what I am trying to prevent now - I want the user to see info on the page and worry less about images hooting up the performance on it)
on my latest attempt:
(function () {
// jquery is unavailable here. using javascript counterpart.
var carouselDivs = document.querySelectorAll('#caruselImagesDivs div[data-url]');
var carouselIndicators = document.querySelector('.carousel-indicators');
var carouselInner = document.querySelector('.carousel-inner');
for (var i = 0; i < carouselDivs.length; i++) {
var liIndicator = document.createElement('LI');
liIndicator.dataset.target = "#property_image_gallery";
liIndicator.dataset.slideTo = i + 1;
var divItem = document.createElement('DIV');
divItem.className = "item";
var image = document.createElement('IMG');
image.dataset.src = carouselDivs[i].dataset.url;
image.classname = 'img-responsive center-block';
// for some reason I thought this might work, but it hasn't.
image.onload = function () {
image.src = image.dataset.src;
image.onload = function () { };
}
image.src = '/Images/blankbeacon.jpg';
divItem.appendChild(image);
carouselIndicators.appendChild(liIndicator);
carouselInner.appendChild(divItem);
}
})();
I tried deferring the loading of the images too (the top code section hadn't had the onload event then):
function initImg() {
var imgs = document.querySelectorAll('#property_image_gallery .carousel-inner .item img');
for (var i = 0; i < imgs.length; i++) {
var imgSource = imgs[i].dataset.src;
imgs[i].src = imgSource;
}
}
window.onload = initImg
2 hours in. no results. I am stumped. What am I missing? how can I force the browser to just move on with life and load those images later on?
At first, you may load images one after one, using recursive functions:
function addimg(img){
img.onload=function(){
addimg(nextimg) ;
img.onload=null;//kill closure -> free the js memory
}
}
Start that if the html is loaded completely:
window.onload=addimg;
(pseudocode)
You can also use a image compressor tool to make the images load faster.
http://optimizilla.com/
This is a great article that might also help you
https://varvy.com/pagespeed/defer-images.html
Few suggestions:
If the images are not in the current viewport and are taking up too much initial bandwidth then i suggest to lazy load images when the user is in (or close to) the same viewport of the images.
You can also try deferring the images like what you are doing, but ensure the script is run right before the end body tag.
I also suggest doing things like making sure images are correctly compressed and resized (you have an image there that is 225kb which isnt ideal)

Load image if found, else load another image

what I need to do is simple to say but (for me) hard to do:
using javascript, given an image name, ie "image01.jpg", I need to check if this image exists in a certain folder or path (local or on the web). If the image does not exist under that folder, I need to check if the same image exists in another folder.
for example, with pseudo code
imageToFind = 'image01.jpg'
path1 = 'users/john/images'
path2 = 'users/mike/img'
if path1+'/'+imageToFind exists
//do something
else
if path2+'/'+imageToFind exists
//do something
else
print('NOT FOUND')
what kind of approach do you suggest? I tryed to achieve this using ajax first, and then using javascript's Image() , but I failed in both these cases.
Thanks in advance for any help, best regards
Use the onerror callback :
var img = new Image();
img.onerror = function(){
img = new Image(); // clean the error (depends on the browser)
img.onerror = function(){
console.log('not found at all !');
};
img.src = path2+'/'+imageToFind;
};
img.src = path1+'/'+imageToFind;
You can pretty much rely on native onload and onerror event handlers which fire for Image nodes. So it could look like
var images = ['users/john/images/image01.jpg','users/mike/img/image01.jpg','some/more/path/image01.jpg'];
(function _load( img ) {
var loadImage = new Image();
loadImage.onerror = function() {
// image could not get loaded, try next one in list
_load( images.shift() );
};
loadImage.onload = function() {
// this image was loaded successfully, do something with it
};
loadImage.src = img;
}( images.shift() ));
This code probably does a little more than you actually asked for. You can basically but as much image paths as you wish into that array, the script will search the list until it could load one image successfully.
try something like
objImg = new Image();
objImg.src = 'photo.gif';
if(!objImg.complete)
{
img.src = path2+'/'+imageToFind; //load other image
}else{
img.src = path1+'/'+imageToFind;
}
I think you need to ask yourself: why don't I know whether the images exist?
I feel like you should not have this problem, or want to solve it in this way.

How to make sure Images are loaded in a loop and in correct order

I am loading images from remote server.
how do i make sure that all images are loaded in correct order
also how do i make sure the alert is called only when all images are loaded
the below code does not load the images in correct order and calls the alert before the images are loaded.
$(window).load(function () {
$('.fancybox').each(function () {
var hh = $(this).attr('href');
var img = new Image();
img.src = hh;
function TIMG(i) {
if (img.complete != null && img.complete == true) {
$('.mag').append('<img src="' + hh + '" class="cls" />');
} else {
setTimeout(TIMG, 1000);
}
}
setTimeout(TIMG, 1000);
});
alert(hi);
});
Based on the new information that you just want to add them in order as soon as they are ready, you can do that like this
$(document).ready(function () {
// preload all the images as fast as possible
var imgs = [];
$('.fancybox').each(function () {
// get all images preloading immediately
// so there is the best chance they are available when needed
var img = new Image();
imgs.push(img);
img.onload = function() {
addReadyImages();
}
img.className = "cls";
img.src = $(this).attr('href');
});
function addReadyImages() {
// show all images that are ready up to here
while (imgs.length && imgs[0].complete === true) {
// append the loaded image from the start of the array
$('.mag').first().append(imgs[0]);
// remove the one we just did from the start of the array
imgs.shift();
}
}
});
Working demo: http://jsfiddle.net/jfriend00/sCHws/
This algorithm works as follows:
Start preloading all the images as soon as possible.
Store the image objects in an array in the order that the .fancybox items are encountered in your page
Set an onload handler for each image so we know immediately when it's ready
In the onload handler for any image, append all images at the front of the array that are ready and then remove them from the array
P.S. I've assumed there is only one .mag item and thus we don't need to make separate copies of the image objects (much more efficient that way - rather than creating new image objects). If that is not the case, then please disclose your HTML so we can see the whole problem.
Since browsers will normally not block when downloading images,the only way to ensure that the images are loaded in the right order would be to load them serially...using a queue and then only beginning the next after the previous has completed. That is definitely not recommended though since that could easily create a severe performance hit.
Waiting for when all of the images are loaded would likely best be done by the .promise() and related methods in jQuery: http://api.jquery.com/promise/, and watching for when the images are load()ed. If you particularly want to control the display of images (which is more likely what you'd be concerned with), then they could be displayed in sequence after they are loaded.

Pre-loading image(s) with JavaScript & jQuery

I'm using the following code to insert some HTML into a div, and to preload any images that might be contained in that HTML (the html var's data is actually fetched from an AJAX request in the real code). This is to prevent the browser from loading the fetched HTML's images upon showing the div (using the slideDown event) - because this results in the effect's fluidity being broken as it loads image mid-transition. I suppose I could use an interlaced JPEG so that the dimensions of the image are known almost immediately, but obviously it'd be nice to get a cleaner method worked out. :P
var html = '<img src="images/test.jpg" alt="test" />';
$('div.content').hide().html(html);
$('div.content img').each(function(){
var img = new Image();
img.src = $(this).attr('src');
$(this).attr('src', img.src);
});
$('div.content').slideDown('normal');
I'm using the Image object and its subsequent assigning as per the advice given here, but unfortunately the image still isn't cached by the browser using this method, because the sildeDown() effect is still interrupted as the image loads.
Any help or alternative methods? Many thanks.
Edit - 21st Sept 09
Progress! Turns out the browser was caching the image, I just wasn't giving it time to do so (it just needed a second to load with an alert() or setInterval()). Now introducing what is probably the messiest code ever - I am using an infinite loop to create that pause.
The new method extends the old code above by binding a function (that adds each image's src to an array) to that image's successful load event. It then gets stuck in an infinite loop as it waits until all the images have loaded and therefore appeared in the array. This seems to work as a way to synchronously pre-load images - but a problem remains; the while() loop for some reason cycles infinitely even once all the images are loaded, unless I add an alert() to pause it for a moment.
The new code:
var html = '<img src="images/test.jpg" alt="test" />';
$('div.content').hide().html(html);
// define usr variables object
$.usrvar = {};
// array of loaded images' urls
$.usrvar.images = [];
// boolean for whether this content has images (and if we should check they are all loaded later)
$.usrvar.hasimages = false;
// foreach of any images inside the content
$('div.content img').each(function(){
// if we're here then this content has images..
$.usrvar.hasimages = true;
// set this image's src to a var
var src = $(this).attr('src');
// add this image to our images array once it has finished loading
$(this).load(function(){
$.usrvar.images.push(src);
});
// create a new image
var img = new Image();
// set our new image's src
img.src = src;
});
// avoid this code if we don't have images in the content
if ($.usrvar.hasimages != false) {
// no images are yet loaded
$.usrvar.imagesloaded = false;
// repeatedly cycle (while() loop) through all images in content (each() loop)
while ($.usrvar.imagesloaded != true) {
$('div.content img').each(function(){
// get this loop's image src
var src = $(this).attr('src');
// if this src is in our images array, it must have finished loading
if ($.usrvar.images.indexOf(src) != -1) {
// set imagesloaded to trueai
$.usrvar.imagesloaded = true;
} else {
// without the pause caused by this alert(), this loop becomes infinite?!
alert('pause');
// this image is not yet loaded, so set var to false to initiate another loop
// (ignores whether imagesloaded has been set to true by another image, because ALL
// need to be loaded
$.usrvar.imagesloaded = false;
}
});
}
}
$('div.content').slideDown('normal');
I made the following solution but it hasn't been tested, so you're warned ;)
// HTML (any formatting possible)
// no src for the images: it is provided in alt which is of the form url::actualAlt
var html = "<p><img alt='images/test.jpg::test' /><br />Some Text<br /><img alt='images/test2.jpg::test2' /></p>";
$(document).ready(function() {
// Reference to the content div (faster)
var divContent = $("div.content");
// Hide the div, put the HTML
divContent.hide().html(html);
// Webkit browsers sometimes do not parse immediately
// The setTimeout(function,1) gives them time to do so
setTimeout(function() {
// Get the images
var images = $("img",divContent);
// Find the number of images for synchronization purpose
var counter = images.length;
// Synchronizer
// will show the div when all images have been loaded
function imageLoaded() {
if (--counter<=0) $('div.content').slideDown('normal');
}
// Loading loop
// For each image in divContent
$.each(images,function() {
// Get the url & alt info from the alt attribute
var tmp = $(this).attr("alt").split("::");
// Set the alt attribute to its actual value
$(this).attr("alt",tmp[1]);
// Wire the onload & onerror handlers
this.onload = this.onerror = imageLoaded;
// Set the image src
this.src = tmp[0];
});
},1);
});
Create an interval/timeout and let it check your compterGenerated css-height, if it's autosized it'll begin from 0 and end to 100 (for example). But in Safari it loads the height before the image, so it'll propably not work in all browsers...
I was playing with this and I created a slightly different solution. Instead of pushing images onto an array when they are loaded, you push them all onto an array in the loop, then in the load event you remove them from the array and call a 'finished' function. It checks if the images array is empty, and if it is then it clears up and shows the content.
var html = '< animg src="images/test.jpg" alt="test" />'; // not allowed to post images...
$('div.content').hide().html(html);
// preload images
// define usr variables object
$.usrvar = {};
// array of loaded images' urls
$.usrvar.images = [];
// initially no images
$.usrvar.hasimages = false;
$('div.content img').each(function() {
// if we're here then this content has images..
$.usrvar.hasimages = true;
// set this image's src to a var
var src = this.src;
// add this image to our images array
$.usrvar.images.push(src);
// callback when image has finished loading
$(this).load(function(){
var index = $.usrvar.images.indexOf(src);
$.usrvar.images.splice(index,1);
finish_loading();
});
// create a new image
var img = new Image();
// set our new image's src
img.src = src;
});
if(!$.usrvar.hasimages) finish_loading();
function finish_loading() {
if($.usrvar.hasimages) {
if($.usrvar.images.length > 0) return;
}
$('div.content').slideDown('normal');
}
Edit: Looking at Julien's post, his method is better. My method works in a similar way but like the original solution keeps track of images by an array of srcs rather than just a count (which is more efficient).
Edit 2: well I thought it was a better solution, but it seems it doesnt work for me. Maybe something to do with the load event getting called too close to each other. Sometimes it will work but sometimes it will hang when loading images, and the image counter never reaches zero. I've gone back to the method in my post above.
Edit 3: It appears it was the setTimeout that was causing the problem.
This is what I use. As you can see by my points, I'm no pro, but I found this somewhere and it works great for me and seems much simpler than everything posted. Maybe I missed a requirement though. :)
var myImgs = ['images/nav/img1.png', 'images/nav/img2.png', 'images/nav/img3.png', 'images/nav/img4.png', 'images/expand.png', 'images/collapse.png'];
function preload(imgs) {
var img;
for (var i = 0, len = imgs.length; i < len; ++i) {
img = new Image();
img.src = imgs[i];
}
}
preload(myImgs);

Categories