setTimeout Problem - javascript

i got a problem with setTimeout.. i dont know why this will not work..
$(document).ready(function(){
var counterNum = 0;
function tick()
{
addText(counterNum);
setTimeout('tick()',1000);
counterNum++;
}
function addText(strNum)
{
$("div.counter").empty();
$("div.counter").append(strNum);
}
});​
you can check it here for the live preview LINK
and also sir, what is the difference between
setTimeout('tick()',1000);
and
setTimeout(tick(),1000);
?

Try:
$(document).ready(function(){
var counterNum = 0;
function tick()
{
addText(counterNum);
setTimeout(tick,1000);
counterNum++;
}
function addText(strNum)
{
$("div.counter").empty();
$("div.counter").append(strNum+"");
}
tick();
});
The difference between
setTimeout('tick()',1000)
and
setTimeout(tick(), 1000)
is that the second one will not wait 1000ms to execute, but if you changed it to
setTimeout(tick, 1000)
it would be effectively the same. Technically, it would change the scope of where the function was called from.

In the case of passing in a string JavaScript has to evaluate it to run your code. With setTimeOut you should always use a pattern like this:
var self = this;
setTimeout(function(){tick();},1000);
This gives you closure and allows you to get around the fact that using setTimeOut changes what this is to be the global object window (a nastly little surprise for developers the first time they encounter it).
Try that in combination with Fredrik recommendeds and you should be in good shape.

Related

Ending a javascript function

I have an html page that links to a js file that has the following function:
function show360Simple( divContainerId, imageUrl )
The function gets called on an on-click:
<area onclick="show360Simple('pContainer5','images/porch1.jpg');">
And I want to know how to end the function with another on-click:
<div id="close-div" onclick="what is the syntax here to end the above function?"></div>
Its probably simple but I'm a novice and haven't been able to work it out yet - any help is greatly appreciated - cheers.
The script linked above is using setTimeout to manage the animation.
To stop, you will need to modify the code a bit and add a stop function.
The simplest approach would be to store off the timeoutId returned from each setTimeout call. Then, in the stop function, call clearTimeout passing in the stored timeoutId.
Without making too many changes:
// Declare a global timeoutId
var timeoutId;
In function show360 change the setTimeout call to:
timeoutId = setTimeout(…);
In function move360 change the setTimeout call to:
timeoutId = setTimeout(…);
Then add a stop360 function:
function stop360() {
clearTimeout(timeoutId);
}
Demo fiddle
This will stop the animation - basically freezing it. If you want to remove the changes made by the script you could change the stop function to something like this:
function stop360(divContainerId) {
clearTimeout(timeoutId);
if(divContainerId) {
var o = document.getElementById(divContainerId);
o.style.backgroundImage = '';
o.style.position = "";
o.innerHTML = "";
}
}
Demo with Clear

Adding text periodically

I am trying to run small snippet code in JavaScript, where I want to write on the web page simple hello world each 5 seconds. I think it must be ok, but no, still I got only first hello world and no more. Could you give me a hand in this? Thanks
<script type="text/javascript">
var i=0;
function startTimer() {
window.setTimeout('refresh()',5000);
}
function refresh() {
document.write("Hello world "+i+"<br/>");
i++;
window.setTimeout('startTimer()',1);
}
startTimer();
</script>
NOTE: As Amar Palsapure has noted in this answer, the root cause of the problem was the use of document.write. In my demonstration, I use a p element to document.body.appendChild() to add the text to the screen.
You can use setTimeout(), but you have to make it contingent on the last setTimeout() that ran; so that each time the caller runs, it creates the next timeout.
setInterval() is designed to run at a "regular" interval (neither setTimeout() nor setInterval() are truly reliable in when they run); however, if the calls to setInterval() get backed up due to some other process blocking it's execution (Javascript is single-threaded), you could have issues with those queued callbacks. That's why I prefer the approach I have below.
Note, refrain from the setTimeout('funcCalled()', 100) usage; this is running an eval() on that string you're passing in, which can change the scope in which you're running the callback, as well as being considered "evil" due to security issues related to eval(). You're best to avoid it altogether.
EDIT - Modified slightly.
I have made some changes to the approach. See my comments.
// The first and last lines comprise a self-executing,
// anonymous function, eg, (function(){})();.
// This allows me to use a local function scope and not the
// global window scope, while still maintaining my variables
// due to it being a "closure" (function(){}).
(function(){
var i = 0,
timer = 5000,
// I'm just going to add this to the DOM.
text = document.createElement('p');
// This is a variable function, meaning it stores a
// reference to a function.
var helloWorld = function() {
// Here is where I add the Hello World statement
text.innerHTML += 'Hello World! Loop: ' + i++ + '<br/>';
// Them add it to the DOM.
document.body.appendChild(text);
// I added this so it wouldn't run forever.
if (i < 100) {
// A setTimeout() will be added each time the last
// was run, as long as i < 100.
// Note how I handle the callback, which is the
// first argument in the function call.
setTimeout(helloWorld, timer);
}
// I added the change so it wouldn't take so long
// to see if was working.
timer = 500;
}
// Here I use a variable function and attach it to the
// onload page event, so it will run when the page is
// done loading.
window.onload = helloWorld;
})();
http://jsfiddle.net/tXFrf/2/
The main issue is document.write. There is nothing wrong with setTimeout or rest of the code.
The reason it does not work is that once document.write is called the first time, it overwrites your existing code of setTimeout() and since there is no code so it will not work.
What you need to do is use some other means to write the value in the page, certainly no document.write...
Instead of using setInterval use setTimeout.
You can try this
<html>
<body>
<div id="clock" ></div>
<script type="text/javascript">
var i = 0,
timerHandle,
clock;
function startTimer() {
clock = document.getElementById('clock');
//You can use timerHandle, to stop timer by doing clearInterval(timerHandle)
timerHandle = self.setInterval(funRefresh, 2000);
}
var funRefresh = function refresh() {
clock.innerHTML += "Hello world " + i++ + "<br/>";
}
startTimer();
</script>
</body>
</html>
Hope this helps you.
Here is the working Code
var i = 0;
function startTimer() {
window.setInterval(refresh, 5000);
}
function refresh() {
document.write("Hello world " + i + "<br/>");
i++;
// window.setTimeout(startTimer,1);
}
startTimer();​

In JQuery, Is it possible to get callback function after setting new css rule?

I have $('.element').css("color","yellow") and I need that next event was only after this one, something looks like $('.element').css("color","yellow",function(){ alert(1); })
I need this because:
$('.element').css("color","yellow");
alert(1);
events are happen at one time almost, and this moment call the bug in animation effect (alert(1) is just here for example, in real module it's animation)
you can use promise
$('.element').css("color","yellow").promise().done(function(){
alert( 'color is yellow!' );
});
http://codepen.io/onikiienko/pen/wBJyLP
Callbacks are only necessary for asynchronous functions. The css function will always complete before code execution continues, so a callback is not required. In the code:
$('.element').css('color', 'yellow');
alert(1);
The color will be changed before the alert is fired. You can confirm this by running:
$('.element').css('color', 'yellow');
alert($('.element').css('color'));
In other words, if you wanted to use a callback, just execute it after the css function:
$('.element').css('color', 'yellow');
cb();
You can use setTimeout to increase the sleep time between the alert and the css like this:
function afterCss() {
alert(1);
}
$('.element').css("color","yellow");
setTimeout(afterCss, 1000);
This will make the alert appear 1 second after the css changes were committed.
This answer is outdated, so you might want to use promises from ES6 like the answer above.
$('.element').css("color", "yellow").promise().done(function(){
// The context here is done() and not $('.element'),
// be careful when using the "this" variable
alert(1);
});
There's no callback for jquery css function. However, we can go around, it's not a good practice, but it works.
If you call it right after you make the change
$('.element').css('color','yellow');
alert('DONE');
If you want this function has only been called right after the change, make an interval loop.
$('.element').css('color','yellow');
var detectChange = setInterval(function(){
var myColor = $('.element').css('color');
if (myColor == 'yellow') {
alert('DONE');
clearInterval(detectChange); //Stop the loop
}
},10);
To avoid an infinite loop, set a limit
var current = 0;
$('.element').css('color','yellow');
current++;
var detectChange = setInterval(function(){
var myColor = $('.element').css('color');
if (myColor == 'yellow' || current >= 100) {
alert('DONE');
clearInterval(detectChange); //Stop the loop
}
},10);
Or using settimeout as mentioned above/
use jquery promise,
$('.element').css("color","yellow").promise().done(function(){alert(1)});

setTimeout in methods of multiple objects of the same type

I need help with the use of "setTimeout" in the methods of the objects of the same type. I use this code to initiate my objects:
function myObject(param){
this.content = document.createElement('div');
this.content.style.opacity = 0;
this.content.innerHTML = param;
document.body.appendChild(this.content);
this.show = function(){
if(this.content.style.opacity < 1){
this.content.style.opacity = (parseFloat(this.content.style.opacity) + 0.1).toFixed(1);
that = this;
setTimeout(function(){that.show();},100);
}
}
this.hide = function(){
if(this.content.style.opacity > 0){
this.content.style.opacity = (parseFloat(this.content.style.opacity) - 0.1).toFixed(1);
that = this;
setTimeout(function(){that.hide();},100);
}
}
}
Somewhere I have 2 objects:
obj1 = new myObject('Something here');
obj2 = new myObject('Something else here');
Somewhere in the HTML code I use them:
<button onclick="obj1.show()">Something here</button>
<button onclick="obj2.show()">Something else here</button>
When the user presses one button, everything goes OK, but if the user presses one button and after a short time interval he presses the other one, the action triggered by the first button stops and only the action of the second button is executed.
I understand that the global variable "that" becomes the refence of the second object, but I don't know how to create an automatic mechanism that wouldn't block the previously called methods.
Thank you in advance and sorry for my English if I made some mistakes :P
If you need something cancellable, use window.setInterval instead of setTimeout. setInterval returns a handle to the interval which can then be used to cancel the interval later:
var global_intervalHandler = window.setInterval(function() { ... }, millisecondsTotal);
// more code ...
// later, to cancel this guy:
window.clearInterval(global_intervalHandler);
So from here I'm sure you can use your engineering skills and creativity to make your own self expiring operations - if they execute and complete successfully (or even unsuccessfully) they cancel their own interval. If another process intervenes, it can cancel the interval first and hten fire its behavior.
There are several ways to handle something like this, here's just one off the top of my head.
First of all, I see you're writing anonymous functions to put inside the setTimeout. I find it more elegant to bind a method of my object to its scope and send that to setTimeout. There's lots of ways to do hitching, but soon bind() will become standard (you can write this into your own support libraries yourself for browser compatibility). Doing things this way would keep your variables in their own scope (no "that" variable in the global scope) and go a long way to avoiding bugs like this. For example:
function myObject(param){
// ... snip
this.show = function(){
if(this.content.style.opacity < 1){
this.content.style.opacity = (parseFloat(this.content.style.opacity) + 0.1).toFixed(1);
setTimeout(this.show.bind(this),100);
}
}
this.hide = function(){
if(this.content.style.opacity > 0){
this.content.style.opacity = (parseFloat(this.content.style.opacity) - 0.1).toFixed(1);
setTimeout(this.hide.bind(this),100);
}
}
}
Second, you probably want to add some animation-handling methods to your object. setTimeout returns handles you can use to cancel the scheduled callback. If you implement something like this.registerTimeout() and this.cancelTimeout() that can help you make sure only one thing is going on at a time and insulate your code's behavior from frenetic user clicking like what you describe.
Do you need that as global variable ? just change to var that = this; you will use variable inside of the function context.

SetInterval inside scrolling events on iPhone - Why this code doesn't work?

Please, take a look at this code (I'm using Zepto http://zeptojs.com/ BTW)...
var timer = false;
$(window).bind('touchstart touchmove scroll', function (e) {
if (timer === false) {
timer = setInterval(function () {
$('footer').css('top', (this.pageYOffset + this.innerHeight - 40) + 'px');
console.log('Adjusted...');
}, 100);
}
}).bind('touchend', function () {
clearInterval(timer);
timer = false;
console.log('Cleaned it up...');
});
As you can see, I have a footer element that I'm trying to keep fixed on the bottom of the iPhone screen. I know that there are libraries that helps us make this quite easily like iScroll 4 http://cubiq.org/iscroll-4, but I was trying to see if I could make it simpler.
It turns out that the code above doesn't work properly. While I'm actually scrolling the page, for some reason setInterval doesn't execute but instead seems to pile up on the background to run every call at the same time.
At the end it doesn't do what I wanted it to do, which is to "animate" the footer and have it in place during scroll not only after. Does anyone has any idea on how such effect could be achieved on some similar manner?
Thanks!
When you pass a method to setInterval() (or any other function, for that matter), it will be invoked with a wrong this value. This problem is explained in detail in the JavaScript reference.
MDC docs
Inside your outer callback, this will be the DOM element you care about, but inside the setInterval callback, this will be window. Keep in mind that this is a keyword, not a variable, and that it is highly context sensitive.
The usual approach is to capture the value of this in a variable and then use that variable instead of this:
if(timer === false) {
var self = this; // "_that" is also a common name for the variable.
timer = setInterval(function () {
$('footer').css('top', (self.pageYOffset + self.innerHeight - 40) + 'px');
console.log('Adjusted...');
}, 100);
}
Similar issues apply to all callbacks in JavaScript, always make sure you know what this is and grab its value and build a closure over that value when it won't be what you want.

Categories

Resources