Reload multiple images using jQuery? How to optimize? - javascript

I have an update of multiple images using jQuery:
window.onload = function () {
setInterval(function () {
$(".image").each(function (index) {
base_url = $(this).attr('src').split('?rand=')[0];
address = base_url + '?rand=' + Math.random();
$(this).attr("src", address);
});
}, 10000);
};
I'm trying to improve it:
function update() {
setInterval(function () {
$(".cameragrid_").find("img").each(function (index) {
d = new Date();
var src = $(this)[0].src;
var state = $(this).context.readyState;
if (state == 'complete'); {
$(this).attr("src", src + d.getTime());
}
});
console.log('click');
}, 10000);
}
$(window).ready(function () {
$('.cameragrid_').hide();
});
$(window).load(function () {
$('.cameragrid_').show();
update();
});
I wanted to reduce the time from 10 to 3 seconds, but when I reduce this time, do not update all the images, my algorithm and the rest is not updated.
.
Is there any way to optimize it to run within 3 seconds ?

instead of having one timer for many images maybe you could try to have many timers, one for each image or at least a small batch of images.
window.onload = function () {
$(".image").each(function (index) {
setInterval(function () {
base_url = $(this).attr('src').split('?rand=')[0];
address = base_url + '?rand=' + Math.random();
$(this).attr("src", address);
}, 3000);
});
};
I've not tested this code but you can get the idea, maybe you'll have to add a $.proxy() somewhere to fix the this context.
testing if the image is displayed should be easier this way: https://www.customd.com/articles/13/checking-if-an-element-is-visible-on-screen-using-jquery

Hey have you tried https://tinypng.com/ this compress the image format, this will increase some loading time of image more over you can also work on making the sprite of 10 images into 1 in this way loading only one file and then indexing the sprite.
Never personally tried image-min but this is also worth looking.
Believe sprite could solve your problem in shot.

I ended that way:
setInterval(function(){
$( ".image" ).each(function( index ) {
var img = new Image();
img.src = $(this).attr('src');
if(img.complete){
base_url = $(this).attr('src').split('?rand=')[0];
address = base_url + '?rand=' + Math.random();
$(this).attr("src", address);
}
});
},500);

Related

Lazy Load function broken

I have this lazy loading function. On execution it first loads a small version of the image and later loads the full version. I needed this to quickly give the user a working slideshow before starting to load the really big images.
It all worked before I added in the last if statement:
if (!$(this).hasClass('lazyLoaded'))
And the mutations to the class after loading each image:
$(this).addClass('lazyLoaded');
I want to check if the images had been loaded before. I need this, because else on a next execution, the script would replace the full sized images with the smaller images and then later reloading the large images.
When I add this extra if statement and the 2 .addClass operations, the script stops working. I have no clue why, can you help me?
A weird side-effect I also noticed is the counting of the image length was 1 too high.
html:
<img src="img/3x2.gif" data-src="img/photo/event.jpg" alt="" />
<img src="img/3x2.gif" data-src="img/photo/wedding.jpg" alt="" />
<img src="img/3x2.gif" data-src="img/photo/portrait.jpg" alt="" />
jQuery:
$.fn.lazyLoad = function(){
if($(this).is('img[data-src]')) {
var lazy = $(this);
} else {
var lazy = $(this).find('img[data-src]');
};
var lazyLength = $(lazy).length;
console.log('lazyLength = ' + lazyLength);
var lazyNumber = 0
$(lazy).each(function(){
if (!$(this).hasClass('lazyLoaded')) {
if (loadTime > 300) {
var src = $(this).data('src');
var srcPath = src.slice(0, -4);
var srcExt = src.slice(-4);
var srcNew = srcPath + '_s' + srcExt;
$(this).one('load', function(){
lazyNumber++;
console.log('lazyNumber = ' + lazyNumber);
if (lazyNumber >= lazyLength) {
console.log('all small images have been loaded');
console.log('setting Timeout for 500ms');
setTimeout(function() {
console.log('beginning loading of large images...');
$(lazy).each(function(){
$(this).one('load', function(){
console.log('large images loaded');
$(this).addClass('lazyLoaded');
}).attr('src', $(this).data('src'));
});
}, 500);
};
}).attr('src', srcNew);
console.log('small image loaded');
} else {
$(this).one('load', function(){
$(this).addClass('lazyLoaded');
console.log('large images loaded immediately');
}).attr('src', $(this).data('src'));
};
};
});
};
I think the error was created by adding the if statement within the .each loop. When I thought about it, it was not the most efficient way either.
I just have to test the images for both having a data-src attribute and not being loaded already (thus having the class '.lazyLoaded', before passing them to the var lazy array.
So I still add the '.lazyLoaded' class on load of the large image
$(this).one('load', function(){
console.log('large images loaded');
$(this).addClass('lazyLoaded');
}).attr('src', $(this).data('src'));
And in the beginning of the function I added .not('.lazyLoaded')
if($(this).is('img[data-src]')) {
var lazy = $(this).not('.lazyLoaded');
} else {
var lazy = $(this).find('img[data-src]').not('.lazyLoaded');
};
Just posting the entire working code, maybe it is of use to someone with a similar problem:
$.fn.lazyLoad = function(){
if($(this).is('img[data-src]')) {
var lazy = $(this).not('.lazyLoaded');
} else {
var lazy = $(this).find('img[data-src]').not('.lazyLoaded');
};
var lazyLength = $(lazy).length;
console.log('lazyLength = ' + lazyLength);
var lazyNumber = 0
console.log('lazyNumber = ' + lazyNumber);
$(lazy).each(function(){
if (loadTime > 300) {
var src = $(this).data('src');
var srcPath = src.slice(0, -4);
var srcExt = src.slice(-4);
var srcNew = srcPath + '_s' + srcExt;
$(this).one('load', function(){
lazyNumber++;
console.log('lazyNumber = ' + lazyNumber);
if (lazyNumber >= lazyLength) {
console.log('all small images have been loaded');
console.log('setting Timeout for 500ms');
setTimeout(function() {
console.log('beginning loading of large imags...');
$(lazy).each(function(){
$(this).one('load', function(){
console.log('large images loaded');
$(this).addClass('lazyLoaded');
}).attr('src', $(this).data('src'));
});
}, 500);
};
}).attr('src', srcNew);
console.log('small image loaded');
} else {
$(this).one('load', function(){
console.log('large images loaded immediately');
$(this).addClass('lazyLoaded');
}).attr('src', $(this).data('src'));
};
});
};
$('.lazy').lazyLoad();

Jquery Animations not waiting for callback

I have a Jquery animation that is running the code from its function before the animation is complete. the Page this code is being used at is no where near complete yet but if you want to take a look it's cottageboards.com/orderform
$('#snow').fadeIn(500, "linear", function () {
$('#largeImage').fadeOut(500, function () {
$('#largeImage').attr('src', selectedimg).load(function () {
$('#largeImage').fadeIn(1000, function () {
//Everything below here is running before the above image's fade in is complete
$('#snow').fadeOut(5000);
var selection = 'input[name="' + $(selectionage).data('type') + '_selection"]';
$($('#selected_thumb').val()).attr('src', $($('#selected_thumb').val()).data('regular'));
$(selectionage).attr('src', $(selectionage).data('selected'));
selectedid = '#' + $(selectionage).attr('id');
$('#selected_thumb').val(selectedid);
$('#selected_info').html($(selectionage).data('desc'));
$('#name').html($(selectionage).data('name'));
if ($(selectionage).data('val') === 99) {
$('#upload').show();
$('#displayinfo').hide();
} else {
$(selection).val($(selectionage).data('val'));
$('#upload').hide();
$('#displayinfo').show();
}
$('#next').prop('disabled', false);
});
});
});
});
When rewritten so the load function comes before the src change it works like a charm. Thanks for the help guys!
Working code:
$('#snow').fadeIn(500, "linear", function () {
$('#largeImage').fadeOut(500, function () {
$('#largeImage').unbind().load(function () {
$('#largeImage').fadeIn(1000, function () {
$('#snow').fadeOut(5000);
var selection = 'input[name="' + $(selectionage).data('type') + '_selection"]';
$($('#selected_thumb').val()).attr('src', $($('#selected_thumb').val()).data('regular'));
$(selectionage).attr('src', $(selectionage).data('selected'));
selectedid = '#' + $(selectionage).attr('id');
$('#selected_thumb').val(selectedid);
$('#selected_info').html($(selectionage).data('desc'));
$('#name').html($(selectionage).data('name'));
if ($(selectionage).data('val') === 99) {
$('#upload').show();
$('#displayinfo').hide();
} else {
$(selection).val($(selectionage).data('val'));
$('#upload').hide();
$('#displayinfo').show();
}
$('#next').prop('disabled', false);
});
}).attr('src', selectedimg);
});
});
You are binding the load function to largeimage every time you click. The first click the load function gets called once, the second time, it gets called twice. I suspect everything is getting messed up because you are firing multiple .fadeIns on the same object, and they are running in parallel.
Only call $('#largeImage').load(...) once, not on every click. Of course, you'll have to do something about your captured vars, but that's a different issue. Alternatively, call $('#largeImage').unbind().load(...)
If that's hard to follow, replace this line:
$('#largeImage').attr('src', selectedimg).load(function () {
with:
$('#largeImage').unbind().attr('src', selectedimg).load(function () {
I tested it by putting a break point after this line:
$('#thumbs').delegate('img','click', function() {
and calling $('#largeImage').unbind(); and everything seemed to work, so you can do it that way too.
see this fiddle for example how to use done : http://jsfiddle.net/gcnes8b2/1/
$('span').click(function() {
$('#1').fadeIn({
duration: 1000,
done:function(){
$('#2').fadeOut(1000);
// etc
}
});
});

How to pass variable asyncronously through different scripts

I can't figure out how to do it.
I have two separate scripts. The first one generates an interval (or a timeout) to run a specified function every x seconds, i.e. reload the page.
The other script contains actions for a button to control (pause/play) this interval.
The pitfall here is that both sides must be asyncronous (both run when the document is loaded).
How could I properly use the interval within the second script?
Here's the jsFiddle: http://jsfiddle.net/hm2d6d6L/4/
And here's the code for a quick view:
var interval;
// main script
(function($){
$(function(){
var reload = function() {
console.log('reloading...');
};
// Create interval here to run reload() every time
});
})(jQuery);
// Another script, available for specific users
(function($){
$(function(){
var $playerButton = $('body').find('button.player'),
$icon = $playerButton.children('i');
buttonAction = function(e){
e.preventDefault();
if ($(this).hasClass('playing')) {
// Pause/clear interval here
$(this).removeClass('playing').addClass('paused');
$icon.removeClass('glyphicon-pause').addClass('glyphicon-play');
}
else {
// Play/recreate interval here
$(this).removeClass('paused').addClass('playing');
$icon.removeClass('glyphicon-play').addClass('glyphicon-pause');
}
},
buttonInit = function() {
$playerButton.on('click', buttonAction);
};
buttonInit();
});
})(jQuery);
You could just create a simple event bus. This is pretty easy to create with jQuery, since you already have it in there:
// somewhere globally accessible (script 1 works fine)
var bus = $({});
// script 1
setInterval(function() {
reload();
bus.trigger('reload');
}, 1000);
// script 2
bus.on('reload', function() {
// there was a reload in script 1, yay!
});
I've found a solution. I'm sure it's not the best one, but it works.
As you pointed out, I eventually needed at least one global variable to act as a join between both scripts, and the use of a closure to overcome asyncronous issues. Note that I manipulate the button within reload, just to remark that sometimes it's not as easy as moving code outside in the global namespace:
Check it out here in jsFiddle: yay! this works!
And here's the code:
var intervalControl;
// main script
(function($){
$(function(){
var $playerButton = $('body').find('button.player'),
reload = function() {
console.log('reloading...');
$playerButton.css('top', parseInt($playerButton.css('top')) + 1);
};
var interval = function(callback) {
var timer,
playing = false;
this.play = function() {
if (! playing) {
timer = setInterval(callback, 2000);
playing = true;
}
};
this.pause = function() {
if (playing) {
clearInterval(timer);
playing = false;
}
};
this.play();
return this;
};
intervalControl = function() {
var timer = interval(reload);
return {
play: function() {
timer.play();
},
pause: function(){
timer.pause();
}
}
}
});
})(jQuery);
// Another script, available for specific users
(function($){
$(function(){
var $playerButton = $('body').find('button.player'),
$icon = $playerButton.children('i'),
interval;
buttonAction = function(e){
e.preventDefault();
if ($(this).hasClass('playing')) {
interval.pause();
$(this).removeClass('playing').addClass('paused');
$icon.removeClass('glyphicon-pause').addClass('glyphicon-play');
}
else {
interval.play();
$(this).removeClass('paused').addClass('playing');
$icon.removeClass('glyphicon-play').addClass('glyphicon-pause');
}
},
buttonInit = function() {
$playerButton.on('click', buttonAction);
interval = intervalControl();
};
buttonInit();
});
})(jQuery);
Any better suggestion is most welcome.

How to rollover image with time delay?

Actually in the products page, we want to reduce the burden on the server to bring the images only after delay of 2 to 3 seconds on mouse over. So If the user hover the cursor we should hit the server after 2 seconds and bring the new image. But the below code is not working as per our expectation.
HTML Tag:
<img class="rollover-images" data-rollover="{bringNewImage()}" src="{bringOldImage()}" />
Javascript:
$('.rollover-images').each(function() {
var newSrc = $(this).data('rollover');
if(newSrc == 0) return;
var timeout, oldSrc;
$(this).hover(function() {
timeout = setTimeout(function() {
oldSrc = $(this).attr('src');
$(this).attr('src', newSrc).stop(true,true).hide().fadeIn(1);
}, 2000);
}, function() {
clearTimeout(timeout);
$(this).attr('src', oldSrc).stop(true,true).hide().fadeIn(1);
});
});
There are several problems with the posted code
You cannot put in a javascript function for an HTML attribute and expect it to be replaced by the function return value. So your HTML should be
<img class="rollover-images" data-rollover="new.png" src="old.png" />
You have a problem with this inside the timeout function. Since you have begun a new function scope, the value of this won't be your img node. So your JS should be
$(this).hover(function () {
var self = this
timeout = setTimeout(function () {
oldSrc = $(self).attr('src');
$(self).attr('src', newSrc).stop(true, true).hide().fadeIn(1);
}, 2000);
}, function () {
clearTimeout(timeout);
$(this).attr('src', oldSrc).stop(true, true).hide().fadeIn(1);
});
Notice that we defined a new variable called self which is used inside the setTimeout call.

Image Preloader Getting Stuck in IE8

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

Categories