My preloader seems unstable on iPad, even though it works perfectly in all major browsers on both PC and MAC.
Sometimes it works, sometimes it don't, but if I clear the cache, it allmost allways fails on first try.. I'm really stuck here, so any help would be appreciated!
This is my code:
function preloadimages(arr){
var newimages=[], loadedimages=0
var postaction=function(){}
var arr=(typeof arr!="object")? [arr] : arr
function imageloadpost(){
loadedimages++
if (loadedimages==arr.length){
postaction(newimages) //call postaction and pass in newimages array as parameter
}
}
for (var i=0; i<arr.length; i++){
newimages[i]=new Image()
newimages[i].src=arr[i]
newimages[i].onload=function(){
imageloadpost()
}
newimages[i].onerror=function(){
imageloadpost()
}
}
return { //return blank object with done() method
done:function(f){
postaction=f || postaction //remember user defined callback functions to be called when images load
}
}
}
$(document).ready(function(){
preloadimages(['img/bg_joejuice.jpg',
'img/bg_facebook.jpg',
'img/bg_webshop.jpg',
'img/bg_spotify.jpg',
'img/btn_grey_down.png',
'img/btn_pink_down.png',
'img/coffee_active.png',
'img/juice_normal.png',
'img/sandwich_active.png',
'img/remove_down.png',
'img/inc_down.png',
'img/dec_down.png',
'img/checkbox_unchecked.png',
'img/hide_spotify.png',
'img/logo_facebook_active.png',
'img/logo_joejuice.png',
'img/logo_spotify_active.png',
'img/logo_webshop_active.png',
'img/checkbox_unchecked.png',]
).done(function(){
console.log("loaded");
});
});
EDIT:
Sorry for not specifying..
I get no errors in console (related), and it doesn't get to the point where it logs the "loaded" comment.
http://md4a1215.keaweb.dk
NEW EDIT
I got 19 pictures. It runs the forloop 19 times. When the error occur, I usually get 18 "onload" (but has seen as low as 16) and never any "onerror".
It looks like it's the onerror function that isn't triggered (allthough it DOES trigger i all major browsers on both MAC and PC, and it does trigger on the iPad if I just remove one of the images thst id included in the list).. Does this sound right? - And if it does, how can I get this to work?
Your code appears to increment loadedimages onerror as well as onload. Try something like this (this retries the preload on error, and skips the image if it fails maxattempts times)
function preloadimages(arr) {
var newimages = [], loadedimages=0, attempts = 0, maxattempts = 5;
var postaction=function(){};
var arr=(typeof arr!='object') ? [arr] : arr;
function imageloadpost(){
if (loadedimages == newimages.length){ console.log('Preloading of images complete. Loaded ' + newimages.length + ' images of ' + arr.length + '. Processing postaction.'); postaction(newimages); }
}
for (var i=0; i<arr.length; i++){
newimages[i]=new Image();
newimages[i].src=arr[i];
newimages[i].onload=function(){
console.log('Loaded ' + loadedimages + ' ' + this.src);
attempts=0;
loadedimages++;
imageloadpost();
};
newimages[i].onerror=function(){
attempts++;
if(attempts < maxattempts){
console.log('Failed to load: ' + this.src + ' trying again');
this.src = this.src;
}
else{
console.log('Skipping ' + this.src);
var tSrc = this.src;
var thisIndex = -1;
for(var i=0; i <arr.length; i++)
{
if(newimages[i].src === tSrc)
{
thisIndex = i;
}
}
attempts=0;
if(thisIndex >= 0)
{
console.log('Removing ' + tSrc + ' from image list due to failure to load.');
newimages.splice(thisIndex,1);
}
else
{
console.log('Error encountered, could not find ' + tSrc + ' in newimages.');
loadedimages++;
}
imageloadpost();
}
};
} //end of for loop
return { done: function(f) { postaction = f || postaction } }
}
$(document).ready(function(){
preloadimages(['img/image1.jpg','img/image2.jpg','img/image3.jpg']).done(function() { console.log('Function preloadimages is done'); });
});
Related
I'm trying to create a page that changes every 10 seconds 4 times and then begins again. To do this I made a counter and passed it along with my function. It doesn't even seem like its loading.
I tried using <body onload="start()"> as well.
<script>
var i = 1;
function start(){
i = setInterval(changeEdu, 10000, i);
}
function changeEdu(i){
if(i == 4){
i = 1;
}else{
i++;
}
document.getElementById("edu1").src = "left" + i + ".jpg";
document.getElementById("edu2").src = "right" + i + ".jpg";
return i;
}
</script>
By declaring i as a parameter of your function, your increment will only mutate the local variable and not your global state. Also the return value is ignored.
var i = 1;
function start() {
setInterval(changeEdu, 10000);
}
function changeEdu() {
// ^^
if (i == 4) {
i = 1;
} else {
i++;
}
document.getElementById("edu1").src = "left" + i + ".jpg";
document.getElementById("edu2").src = "right" + i + ".jpg";
}
I believe it is because you are reassigning variable i at the onset of the start() function. setInterval returns a number that is used to cancel the function with the clearInterval(theNumber) function.
I am also quite new to JS, but I would try to delete the reassignment in the start() function and try again.
That is not how setInterval works, it doesn't return your return value.
You need to create a closure.
Also, your startInterval() is never called.
Change it to this and it works:
<script>
(function(){
var i = 1;
function changeEdu(){
if(i == 4){
i = 1;
}else{
i++;
}
// document.getElementById("edu1").src = "left" + i + ".jpg";
// document.getElementById("edu2").src = "right" + i + ".jpg";
console.log(i);
}
setInterval(changeEdu, 10000);
})();
</script>
I am making my own version of simon Game, but the callback function inside click is not existing after user press wrong input. As a result function handler.patternRepeatPlayer() is getting called recursively for each element of array pattern.I want a solution to break from the else after callinghandler.patternRepeatPlayer just once. The program is working fine in strict mode, but only in non-strict mode inside else , I am not able to break from else.
-- can access the project on Git.
https://github.com/santosh1357/simonGame.git
The flow is like from html -> Function simonnGame.PatternGen from PatternGen -> handler.PatternRepeatPlayer -> PatternRepPlayer -> PatternMatcher -> userInput(here if wrong user input in non-strict mode) -> patternRepeatPlayer
This case is failing as in this case else is not existing after calling the function only once.
//Problematic Function.
userInput: function(){
var userPattern = new Array();var id;
$('img').click(function(){
id = parseInt(this.id,10); userPattern.push(id);handler.effect(id);
if(userPattern.indexOf(id) !== simonGame.PATTERN.indexOf(id)){
if($('.chkStrict:checked').val() === "on"){
var audio = new Audio('sounds/wrong.mp3');
audio.play();
setTimeout(function(){window.location.reload(true)},1000);
} else {
var audio = new Audio('sounds/wrong.mp3');
audio.play();
userPattern.length = 0;
handler.repeatFlag = true;
handler.patternRepeatPlayer(); ****//this is getting called recursivelly rather than quiting after calling once****
return ;
}
}
//End Problematic Functiom
I think there is some misunderstanding on how click callback functions work.
//Fullcode
var simonGame = {
COUNT: 0,
PATTERN: [],
SOUND:[{file:'sounds/sa.mp3'},{file:'sounds/re.mp3'},{file:'sounds/ga.mp3'},{file:'sounds/ma.mp3'},{file:'sounds/pa.mp3'},{file:'sounds/dha.mp3'},{file:'sounds/nee.mp3'}],
patternGen: function(){
var randomId;
randomId = Math.floor(Math.random() * 7);
simonGame.PATTERN.push(randomId);
if(simonGame.COUNT > 20){
alert("You have won the game!!");
window.location.reload(true);
}
simonGame.COUNT += 1;
//debugger;
//console.log("increase count true calling count display " + simonGame.COUNT);
handler.countDisplay();
//console.log("count gen true calling patternPlayer with PATTERN " + simonGame.PATTERN );
handler.patternRepeatPlayer();
}, //close patternGen
patternMatcher: function(genPattern){
//console.log("inside patternMatch");
var genPattern = simonGame.patternGen;
//setTimeout(function(){
//console.log("PATEERN: " + simonGame.PATTERN + "COUNT " + simonGame.COUNT );
//calling user input
console.log("calling user Input");
handler.userInput();
setTimeout(function(){
if(handler.repeatFlag === false){ //execute count gen only if repeat flag is false inside user INPUT
genPattern();
}
},simonGame.COUNT*2000);
//console.log("pattern check true, calling pattern gen");
//},simonGame.COUNT*5000); //c`enter code here`lose setTimeout
}, //close patternMatcher
} //close simonGame
var handler = {
countRepPlayer: 0,
repeatFlag: false,
patternRepeatPlayer: function(){
var repeater = setInterval(function(){
handler.effect(simonGame.PATTERN[handler.countRepPlayer]);
handler.countRepPlayer += 1;
if(handler.countRepPlayer > simonGame.COUNT){
clearInterval(repeater);
//setTimeout(function(){
simonGame.patternMatcher();
//},1000);
handler.countRepPlayer = 0;
}
},1000);//close sestInterval
}, //close patternRepeatPlayer
effect: function(id){
var img = document.getElementById(id);
if(img !== null && id !== undefined){
$( img ).fadeIn(100).fadeOut(100).fadeIn(100);//fadeOut(200).fadeIn(200);
//debugger;
var audio = new Audio(simonGame.SOUND[id].file);
audio.play();
//console.log("id inside effect " + id)
}
},//close effect
countDisplay: function(){
document.getElementById("count").innerHTML = "Count: " + simonGame.COUNT;
}, //close countIncrease
userInput: function(){
var userPattern = new Array();var id;
$('img').click(function(){
id = parseInt(this.id,10);
userPattern.push(id);
handler.effect(id);
console.log(" user " + userPattern);
console.log(" pattern " + simonGame.PATTERN);
if(userPattern.indexOf(id) !== simonGame.PATTERN.indexOf(id)){
console.log(" WRONG USER INPUT ");
if($('.chkStrict:checked').val() === "on"){
var audio = new Audio('sounds/wrong.mp3');
audio.play();
setTimeout(function(){window.location.reload(true)},1000);
} else {
console.log("inside else " );
var audio = new Audio('sounds/wrong.mp3');
audio.play();
userPattern.length = 0;
handler.repeatFlag = true;
handler.patternRepeatPlayer(); ****//this is getting called recursivelly rather than quiting after calling once**.**
return ;
}
}
//reset the userPattern Array
if(userPattern.length === simonGame.PATTERN.length){
userPattern.length = 0;
}
}); //close click.
}
} //close handler
Yes, It will be called recursively, because you set interval for it.
Here you can modify your code:
patternRepeatPlayer: function(){
var repeater = setInterval(function(){
handler.effect(simonGame.PATTERN[handler.countRepPlayer]);
handler.countRepPlayer += 1;
if(handler.countRepPlayer > simonGame.COUNT){
clearInterval(repeater);
//setTimeout(function(){
simonGame.patternMatcher();
//},1000);
handler.countRepPlayer = 0;
}
},1000);//close sestInterval
}
To: (EDITED)
function myCallbackFunction(repeater){
handler.effect(simonGame.PATTERN[handler.countRepPlayer]);
handler.countRepPlayer += 1;
if(handler.countRepPlayer > simonGame.COUNT){
clearInterval(repeater);
simonGame.patternMatcher();
handler.countRepPlayer = 0;
}
}
patternRepeatPlayer: function(){
var repeater = setInterval(function() {myCallbackFunction(repeater);}, 1000);
}
And where you need to call it once, just call myCallbackFunction(repeater)
I need to count the number of images loaded into a page after certain time interval ( lets say 6 seconds) then need to do some processing.So after 6 seconds I am invoking scan_images_results ( ) function.
function scan_images_results ( ) {
$.when(count_loaded_image()).then(function() {
window.console.log("i m here");
});
}
function count_loaded_image() {
var counter = 0;
$('img[id^="picThumbImg_"]').imagesLoaded()
.progress( function( instance, image ) {
var result = image.isLoaded ? 'loaded' : 'broken';
console.log( 'image is ' + result + ' for ' + image.img.src );
if(image.isLoaded) {
counter++;
}
});
console.log('counter--'+counter);
}
Output is as below.
counter--0
i m here
image is broken for https://myserver/cgi-bin/sf?f=58343d875e7a10290d0464cabfc276e5.jpg
image is broken for https://myserver/cgi-bin/sf?f=68343d875e7a10290d0464cabfc276e6.jpg
image is broken for https://myserver/cgi-bin/sf?f=78343d875e7a10290d0464cabfc276e7.jpg
.........
........ 28 times
I am using "https://github.com/desandro/imagesloaded" to check if image is loaded or not.I am getting 28 images broken, which is correct count.But my counter function is being getting executed later.i.e. my expected output is
image is broken for https://myserver/cgi-bin/sf?f=58343d875e7a10290d0464cabfc276e5.jpg
image is broken for https://myserver/cgi-bin/sf?f=68343d875e7a10290d0464cabfc276e6.jpg
image is broken for https://myserver/cgi-bin/sf?f=78343d875e7a10290d0464cabfc276e7.jpg
.........
........ 28 times
counter--0
I m here
I know where is the problem? I need to execute the function in sequence and for that I need to create Deferred Objects. But I could not ab able to fix my problem.
You don't need $.when, you don't even need the additional function.
function scan_images_results() {
var counter = 0;
$('img[id^="picThumbImg_"]').imagesLoaded()
.progress(function (instance, image) {
var result = image.isLoaded ? 'loaded' : 'broken';
console.log('image is ' + result + ' for ' + image.img.src);
if (image.isLoaded) {
counter++;
}
})
.always(function () {
console.log("I'm here");
});
console.log('counter--' + counter);
}
and if you wanted to keep the function,
function scan_images_results() {
count_loaded_image().always(function () {
console.log("I'm here");
});
}
function count_loaded_image() {
var counter = 0;
return $('img[id^="picThumbImg_"]').imagesLoaded().progress(function (instance, image) {
var result = image.isLoaded ? 'loaded' : 'broken';
console.log('image is ' + result + ' for ' + image.img.src);
if (image.isLoaded) {
counter++;
}
});
}
If I have a callback function within a callback function I can't reach the variables declared inside the first callback.
See example (Uses some jquery):
my fiddle
Why is this?
Or
What am I doing wrong!?
I am using this in the following:
$('<div/>').html(data).find('load').each(function(id, deze) {
var method = $(deze).attr("method");
var animate = $(deze).attr("animate");
var locatie = $(deze).attr("id");
var html = $(deze).html();
if(!method){
method = 'overide';
}
if(!locatie){
error('A002','No loadloc');
}
if(!html){
html = '';
}
if(!animate){
animate = false;
}
else if(animate == 'fade'){
var effectout = 'fade';
var timeout = 100;
var optionsout = {
easing: 'swing'
};
var effectin = 'fade';
var timein = 600;
var optionsin = {
easing: 'swing'
};
}
else{
animate = false;
error('A006','Animation: "' + animate + '" does not exist');
}
//here I make callback or direct function call
if(animate){
$('#' + locatie).hide(effectout, optionsout, timeout, load());
}
else{
load();
}
function load(){
console.log('hallo');
console.log(html);
if(method == 'overide'){
$('#' + locatie).html(html);
}
else if(method == 'tablerow'){
var html = $('tr', deze).html();
$('#' + locatie).html(html);
}
else if(method == 'append'){
$('#' + locatie).append(html);
}
else if(method == 'prepend'){
$('#' + locatie).prepend(html);
}
else{
error('A007','load method: "' + method + '" does not exist');
}
if(animate){
$('#' + locatie).show(effectin, optionsin, timein);
}
}
});
Why is this?
It is not. You can simply access something, it is in the scope of the load function that you posted.
What am I doing wrong!?
You're not passing the load function itself as the callback, but it's result - you're immediately calling it (without arguments). You want
$('#' + locatie).hide(effectout, optionsout, timeout, load);
// ^^
//It seems I can't reach html and other variables here
console.log(this.html);
That's not a variable, that's a property of this (and the this keyword points to different things in the different calls). What you want is a simple variable:
console.log(html);
Same story for this.locatie and the others.
I changed your code a bit and I believe this is what you were trying to do:
http://jsfiddle.net/smerny/2M6k3/
var anothercallbackfunctiontriggerthing = function(cb) {
cb();
}
$('.something').each(function(id, value) {
var something = 'something';
var load = function(){
// can't reach something here
console.log(something);
}
anothercallbackfunctiontriggerthing(load);
});
As load() didn't return anything, I assume you were wanting to pass it as a callback (load) and then call it from within anothercallbackfunctiontriggerthing. The above code will print "something" for each .something.
The reason it doesn't work is because the keyword this changes meanings within the context of load() since you're defining a function using function load(). There are several ways of getting around this; here's one:
Before:
if(animate){
$('#' + locatie).hide(effectout, optionsout, timeout, load());
}
else{
load();
}
use
var load = (function(el) {
return function() {
console.log('hallo');
//It seems I can't reach html and other variables here
console.log(el.html);
if(method == 'overide'){
$('#' + el.locatie).html(el.html);
}
else if(method == 'tablerow'){
var html = $('tr', deze).html();
$('#' + el.locatie).html(el.html);
}
else if(method == 'append'){
$('#' + el.locatie).append(el.html);
}
else if(method == 'prepend'){
$('#' + el.locatie).prepend(el.html);
}
else{
error('A007','load method: "' + el.method + '" does not exist');
}
if(el.animate){
$('#' + el.locatie).show(el.effectin, el.optionsin, el.timein);
}
};
})(this);
What I did there was to change all references to this with el. And then I injected this as el by using the following format:
load = ( function(el) { return yourFunction() {...}; })(this);
Let me know if that makes sense and if it works for you :)
When I try to run the following code in my program
setTimeout("alert('moo')", 1000);
I get the following error
Error: Object expected
Code: 800A138F
Source: Microsoft JScript runtime error
Why? Am I calling the wrong function? What I want to do is delay the execution of the subsequent function.
It sounds like you're using setTimeout in a non-browser-based script (Windows Script Host or similar). You can't do that. You can, however, use WScript.Sleep to suspend your script briefly, with which you can achieve a similar effect. Also, alert is not a WSH function; you may want WScript.Echo. More on the WSH reference on MSDN.
setTimeout is a method of the window object provided by web browsers. It's not available to scripts running on Windows Script Host. Those scripts have a single thread of execution from start to finish and have no delay timers.
If you want to pause script execution you can use the Sleep method of the WScript object.
I needed WSH to behave like similar code in browser that uses setTimeout, so here's what I came up with.
Just have your single thread execute everything in a queue. You can keep adding to the queue. The program will only terminate when no functions are left in the queue.
It doesn't support strings for eval, just functions.
function main() {
Test.before();
_setTimeout(Test.timeout1, 1000);
_setTimeout(Test.timeout2, 2000);
_setTimeout(Test.timeout3, 500);
_setTimeout(Test.error, 2001);
Test.after();
}
var Test = function() {
var ld = "---- ";
var rd = " ----";
return {
before : function() {
log(ld + "Before" + rd);
},
after : function() {
log(ld + "After" + rd);
},
timeout1 : function() {
log(ld + "Timeout1" + rd);
},
timeout2 : function() {
log(ld + "Timeout2" + rd);
},
timeout3 : function() {
log(ld + "Timeout3" + rd);
},
error : function() {
log(ld + "error" + rd);
errorFunc();
}
};
}();
var FuncQueue = function() {
var funcQueue = [];
function FuncItem(name, func, waitTil) {
this.name = name;
this.func = func;
this.waitTil = waitTil;
}
return {
add : function(func, name, waitTil) {
funcQueue.push(new FuncItem(name, func, waitTil));
},
run : function() {
while (funcQueue.length > 0) {
var now = new Date().valueOf();
for ( var i = 0; i < funcQueue.length; i++) {
var item = funcQueue[i];
if (item.waitTil > now) {
continue;
} else {
funcQueue.splice(i, 1);
}
log("Executing: " + item.name);
try {
item.func();
} catch (e) {
log("Unexpected error occured");
}
log("Completed executing: " + item.name);
break;
}
if (funcQueue.length > 0 && i > 0) {
if (typeof (WScript) != "undefined") {
WScript.Sleep(50);
}
}
}
log("Exhausted function queue");
}
}
}();
function _setTimeout(func, delayMs) {
var retval = undefined;
if (typeof (setTimeout) != "undefined") {
retval = setTimeout(func, delayMs); // use the real thing if available
} else {
FuncQueue.add(func, "setTimeout", new Date().valueOf() + delayMs);
}
return retval;
}
var log = function() {
function ms() {
if (!ms.start) {
ms.start = new Date().valueOf();
}
return new Date().valueOf() - ms.start; // report ms since first call to function
}
function pad(s, n) {
s += "";
var filler = " ";
if (s.length < n) {
return filler.substr(0, n - s.length) + s;
}
return s;
}
return function(s) {
if (typeof (WScript) != "undefined") {
WScript.StdOut.WriteLine(pad(ms(), 6) + " " + s);
} else {
// find a different method
}
}
}();
FuncQueue.add(main, "main");
FuncQueue.run();
For anybody who is searching for the alert function to work in a stand-alone script (Windows Script Host environment), I recommend checking out jPaq's alert function which is documented here and downloadable here. I have definitely found this new library to be helpful for my stand-alone scripts.