setTimeout and recursive function with parameters - javascript

I'm trying to do something like that :
I want to call the doSomething() function only when the tab has loaded class (it may take 3 or 5 seconds).
function addInfosSinistre(msg){
addInfosSinistreRecursive(msg, 0);
}
function addInfosSinistreRecursive(msg, nbCalls) {
if ($("#tab").hasClass('loaded')) {
doSomething();
}else if (nbCalls < 10) {
setTimeout(addInfosSinistreRecursive(msg, nbCalls+1),500);
}
}
This is not working, it seems like the timer doesn't work. Is there something wrong here ?

What you actually do, is to execute the function addInfosSinistreRecursive and the pass the return value to setTimeout(). What you actually want to do is to pass a function reference.
One way of doing so is to create a closure for the variables like this:
function addInfosSinistreRecursive(msg, nbCalls) {
function timeoutHandler(){
if ($("#tab").hasClass('loaded') ) {
doSomething();
}else if (nbCalls < 10) {
nbCalls += 1;
setTimeout( timeoutHandler, 500 );
}
}
// first execution
timeoutHandler();
}
The function timeoutHandler() can reference the parameters to addInfosSinistreRecursive() and has no parameters of its own. Hence you can pass a reference to it to setTimeout().

Yes, there's definitely something wrong here. You're immediately calling the function and passing undefined to setTimeout() instead of giving it a function to call. This would do what you are trying to do:
function addInfosSinistreRecursive(msg, nbCalls) {
if ($("#tab").hasClass('loaded')) {
doSomething();
}else if (nbCalls < 10) {
setTimeout(addInfosSinistreRecursive.bind(this, msg, nbCalls + 1), 500);
}
}
But the question is why are you trying to do this? It seems like a convoluted way to do whatever it is you are trying to accomplish. You should probably be using an event somewhere when the tab is changed rather than recursively looping and waiting for the tab to change.

Related

wrapping a function in a pollSever function

I am using an already defined function and now want to add a pollServer function to it so that this functions runs over and over. I keep getting errors when I try to wrap the existing function in another. Is there a better way to do this?
function callD(id) {
jQuery('document').ready(function pollServer(){
window.setTimeout(function () {
var ab = document.getElementById('a')
console.log(ab);
var bod = document.getElementById(+id)
if (ab == null) {
bod.style.background='green'
} else {
bod.style.background='blue'
}
}, 1200);
})
}
callD();
pollServer();
pollServer isn't defined where you're calling it. Also id isn't being passed to callD, and you also have a +id which doesn't make sense in a document.getElementByid, since if there's any non-number in the ID, that would be NaN. You're also not polling a server, you're setting a timeout once and doing some work that doesn't involve a server. You would want setInterval for regular polling, or to call the function again on some condition like a failure.
$(document).ready(function () {
var intervalId;
function callD(id) {
function pollServer() {
intervalId = window.setInterval(function () {
var ab = document.getElementById('a')
console.log(ab);
var bod = document.getElementById(id)
if (ab == null) {
bod.style.background='green'
} else {
bod.style.background='blue'
}
}, 1200);
}
pollServer();
}
callD('some-id');
// on some condtion eventually:
clearInterval(intervalId);
})
Yeah, jQuery can make things pretty gnarly with all the nested callbacks. To make the code cleaner and easier to understand, I like to split my functions up and define them all at the top-most level of the script, then compose them together like so:
/**
* this function will check for the existing elements
* and update styles
*/
function setBodyStyle(id) {
var ab = document.getElementById('a');
console.log(ab);
var bod = document.getElementById(+id);
if (ab == null) {
bod.style.background='green';
} else {
bod.style.background='blue';
}
}
/**
* this function will create a timeout or interval
* which will in turn run setBodyStyle()
*/
function pollServer() {
// I think you want setInterval here if you're polling?
// setInterval will run _every_ 1200ms,
// setTimeout only runs once after 1200ms
window.setInterval(function() {
// not sure where you're getting id from,
// but you'll want to pass it here
setBodyStyle();
}, 1200);
}
// when the document is ready, run pollServer()
jQuery(document).ready(pollServer);
Having small functions that do one thing is just best-practice for the reasons I mentioned above. This will help your script be more understandable, which will help you find bugs.
For example, two things I don't understand about your code above:
where does the id variable come from? I don't see you passing it to your function from anywhere
how does your script poll the server? I don't see the code for that anywhere either.
Seemed you mean run the function pollServer every 1.2 sec. If so, you'd need to do two things
Use setInterval rather than setTimeout
Delete the last line for the pollServer function, because it is not accessible from outside the ready function block.

Adding a delay in a javascript loop with variables passed to the function

I'm trying to build a loop function with a delay. I've found this solution here:
How do I add a delay in a JavaScript loop?
...but because I want to use the function several times, I want to pass variables to the function. This is proving difficult. For example, say I've got a function called "animate_block" that I want to call with variable "blah". This function itself calls another function with this variable, then moves the variable forward by 1 until it reaches some limit, with a recursive setTimeout so it doesn't all happen at once. Should it look something like:
animate_block(blah)
function animate_block(ab_blah){
move_block(ab_blah);
ab_blah = ab_blah +1
if(ab_blah <= 10){
setTimeout(animate_block(){ab_blah},30);
}
? And if it shouldn't which bit(s) have I got wrong?
Ta!
setTimeout takes a function as first argument. You can create a function on the fly, which has access to the ab_blah because functions have access to the parent scope.
animate_block(blah);
function animate_block(ab_blah) {
move_block(ab_blah);
ab_blah = ab_blah +1
if (ab_blah <= 10) {
setTimeout(function() { animate_block(ab_blah); }, 30);
}
}
Read this article on closures in JS to get a good understanding.
Here the limit is fixed. We use requestAnimationFrame instead of the 30ms timeout, as animate_block sounds like something visual.
function moveBlock(position) {
'use strict';
console.log('moving to block', position);
return;
}
function animateBlock(position) {
'use strict';
//... in case the call was made with `position` higher then 10 it should not be executed
if(position <= 10) {
moveBlock(position);
//we increase position, but `position++` returns `position` prior to the increment
if (position++ < 10) {
window.requestAnimationFrame(animateBlock.bind(animateBlock, position));
}
}
}
animateBlock(1);
Android < 4.4, IE8 and Opera Mini require a polyfill.

Finish running a function before proceeding in a loop

I want the function in my FOR loop to finish running before going on to the next code but I just can't get it to work.
It should fade in fade out the text "Result" before popping the alert window 'Lucky you' but I would see the alert window loop first before seeing the text. I don't know what I'm doing wrong.
HTML:
<div id="quotes" style="display: none;">Result</div>
Javascript:
function showNextQuote() {
$("#quotes").fadeIn(2000).delay(2000).fadeOut(2000);
}
for (i = 1; i < 4; i++){
showNextQuote(); alert("Lucky you");
};
Since these operations are asynchronous you can't block processing while they're running. Instead, you pass them a function to execute when they complete (called a callback). So chaining them like this would look more like a recursive function than a loop.
(Though this isn't really technically recursion since the asynchronous operations aren't building up a stack. It's semantically/logically very similar to tail recursion though, at least in function structure.)
Something like this:
function showNextQuote(iteration) {
// terminating condition
if (iteration > 4) {
return;
}
// recurse
$("#quotes").fadeIn(2000).delay(2000).fadeOut(2000, function () {
alert("Lucky you");
showNextQuote(iteration + 1);
});
}
showNextQuote(1);
What this does is define the function, which internally passes a reference to itself as a callback to fadeOut. Each callback increments the iteration value by 1. Then after defining the function it's invoked with an initial iteration value of 1.
As said in comments, JavaScript can't do this in a loop, since fadeIn, delay and fadeOut are all asynchronous.
Something like this should work:
function showNextQuote(n) {
if (n > 0) {
$("#quotes").fadeIn(2000).delay(2000).fadeOut(2000, function() {
alert("Lucky you");
showNextQuote(n - 1);
});
}
}
showNextQuote(4);

Confused with set timeout

I'm really confused how these work...the timeout does not seem to keep running it calls begin_anim once and then thats it....
So am hoping someone can see where i went wrong and explain how I implement this?
This is my code:
//test data:
//type = 'up';
//div = document.getElementById('theid');
//marginL = -400;
function timeout_begin(type,div,marginL){
setTimeout(begin_anim(type,div,marginL),1000);
}
function begin_anim(type,div,marginL){
if(type == 'up'){
if(marginL >= '-200'){
if(marginL > '-200'){
div.style.marginLeft = '-200px';
}
return false;
}
marginL += 2;
div.style.marginLeft = marginL+'px';
}
return false;
}
Hope you can help!
You're looking for setInterval!
Also, it's probably better to pass an actual function in, and you can hold a reference to the loop so you can stop it running later if you want to:
var animationLoop = setInterval(function () {
begin_anim(type, div, marginL);
}, 1000);
clearInterval(animationLoop); // This would then stop the loop.
First, you want setInterval, not setTimeout
Second, you'll pass a reference to a function, not a call to a function. Something like:
function timeout_begin(type,div,marginL)
{
setTimeout(
function() {
begin_anim(type,div,marginL);
},
1000
);
}
setTimeout is supposed to call the function only once.
if you want to call the method repeatedly use setInterval(function(){}, 1000/*duration*/)
setTimeout is only expected to execute the function once after the given timeout. See the documentation here: http://www.w3schools.com/jsref/met_win_settimeout.asp
You're probably looking for setInterval (http://www.w3schools.com/jsref/met_win_setinterval.asp) which executes the code at the interval you set until clearInterval is called.

How to clear a javascript timeout thats set within a function

I have a recursive type function in Javascript that runs like this:
function loadThumb(thumb) {
rotate=setTimeout(function() {
loadThumb(next);
}, delay);
}
Note: I've simplified the function to make it easier to read.
I have "a" tags called like this
Load thumb 3
However, they don't clearout the timer, the timer continues to cycle through the function irregardless of the clearTimeout() being called.
Any ideas why? I think it might have something to do with a scope problem or something like that.
Yeah, you need to make rotate a global variable. Simply declare it outside the function like so:
var rotate;
var delay = 1000;
function loadThumb(thumb) {
alert("loading thumb: " + thumb);
rotate = setTimeout(function() {
loadThumb(thumb + 1);
}, delay);
}
Also, you need to make sure you clear the timeout before you call loadThumb. Otherwise you'll clear the timer you just started.
Load thumb 3
fiddle: http://jsfiddle.net/63FUD/
it may be the issue of scope so make rotate as global variable and call clearTimeout(rotate);
refer clearTimeout() example
It may be a scoping issue if you are not declaring rotate externally.
Try this:
var rotate = 0;
function loadThumb(thumb) {
rotate=setTimeout(function() {
loadThumb(next);
}, delay);
}
Return false on the link
Since you are not using var rotate, it should not be a scoping issue since rotate would be in the window scope. Can you show the complete code?
It is considered poor coding to inline the script - you should attach the event handler onload of the page
Also you should not have the setTimeout inside a function that might be called for one image
Try this:
var rotate,next=1;
function loadThumb(thumb) {
if (thumb) ... use thumb
else ... use next
}
function slide() {
rotate=setInterval(function() {
loadThumb();
next++;
if (next>=images.length) next=0;
}, delay);
}
window.onload=function() {
var links = document.getElementsByTagName("a");
if (links[i].className==="thumbLink") {
links[i].onclick=function() {
var idx = this.id.replace("link","");
loadThumb(idx);
clearInterval(rotate);
return false;
}
}
document.getElementById("start").onclick=function() {
slide();
return false;
}
document.getElementById("stop").onclick=function() {
clearInterval(rotate);
return false;
}
slide();
}
assuming
Start
Stop
Show 1
Show 2
Show 3
If you have to manage multiple timeouts, you can use an object in the global scope and some custom methods to create and remove your timeouts. To access the methods you can either put the calls in the onclick handler of your links (like in the example), or use a library like jQuery to bind them.
<script type="text/javascript">
var timeouts = timeouts || {};
function createTimeout(name, milliseconds, callback) {
timeouts.name = setTimeout(callback, milliseconds);
}
function removeTimeout(name) {
if (typeof(timeouts.name) !== undefined) {
clearTimeout(timeouts.name);
timeouts.name = undefined;
}
}
createTimeout('foo', 5000, function() {
alert('timeout')
});
</script>
i have also posted an example on jsFiddle http://jsfiddle.net/AGpzs/
I'm not sure what exactly you are doing, because as far as I can see you didn't post all the code, but this looks better for me:
function loadThumb(thumb) {
return setTimeout(function() {
loadThumb(next);
}, delay);
}
and then:
Load thumb 3

Categories