Javascript - making 2 setInterval() be synchronous - javascript

I have 2 functions calling setInterval but I need them to be synchronous. Here is my code(yes, they are really simple).
var number1 = 0;
function caller(){
go();
come();
}
function go() {
anim1 = setInterval("doActionGo()", 20);
}
function come() {
anim2 = setInterval("doActionCome()", 20);
}
function doActionGo(){
if(number1 < 1023) {
number1++;
} else {
clearInterval(anim1);
}
}
function doActionCome() {
if (number1 > 0) {
number1 = number1 - 1
} else {
clearInterval(anim2);
}
functions doActionGo() and doActionCome() would be any code. Does anybody know how to solve it?
Regards!

To execute two animations in sequence just start the second one at the end of the first... for example:
var anim1, anim2;
var number = 0;
function animation1()
{
number = number + 1;
if (number > 1000)
{
clearInterval(anim1);
anim2 = setInterval(animation2, 20);
}
}
function animation2()
{
number = number - 1;
if (number < 0)
{
clearInterval(anim2);
}
}
function start()
{
anim1 = setInterval(animation1, 20);
}

Here is way to call them in sequence:
var number1 = 0;
function caller(){
go( come );
}
function go(comeFn) {
var anim = setInterval(function(){
if(number1 < 100) {
number1++;
} else {
clearInterval(anim);
comeFn();
}
}, 20);
}
function come() {
var anim = setInterval(function(){
if (number1 > 0) {
number1--;
} else {
clearInterval(anim);
}
}, 20);
}
And two comments:
you shouldn't use strings in setInterval('functionName', 30) but directly functions
if you don't use anim1 instead of var anim1 it is considered as a global variables

See demo of the following →
It wasn't really clear what you were asking, but it inspired me to write this mini animation queue. Maybe you or someone else will benefit from it:
var number1 = 0,
number2 = 1023,
queue = [];
// execute every XX miliseconds
function tick(delay) {
// iterate through queue
for (var i = 0, il = queue.length; i < il; i++) {
if (queue[i]) {
// execute each tick function
queue[i].tick();
}
}
// recall tick
setTimeout(function() {
tick(delay);
}, delay);
}
// kill tick function of matching name
function qKill(name) {
for (var i = 0, il = queue.length; i < il; i++) {
if (queue[i]) {
if (queue[i].name === name) {
queue.splice(i, 1);
}
}
}
}
var go = {
name: 'go',
tick: function() {
if (number1 < number2) {
number1++;
// do whatever here
} else {
qKill('go');
}
}
};
var come = {
name: 'come',
tick: function() {
if (number2 > number1) {
number2 = number2 - 1;
// do whatever here
} else {
qKill('come');
}
}
};
queue.push(go);
queue.push(come);
tick(20);
Demo →

As people already commented, JavaScript is single threaded. So running two functions simultaneously is impossible. However a couple of strategies can be used to simulate this.
For GUI effects, interpolation can be used. Basically, a single function is responsible of transitioning things step by step by interpolating the start and end value(be it an opacity, a position, a variable, a state or whatever can be interpolated). A javascript library can use this simple concept to create effects for example.
A second approach is to use co-routines available in javascript since version 1.7. This article (although a little old) describes how to simulate threading in javascript and can be a good starting point to understand the mechanism involved in a co-routine powered design.
Hope this will help :)

Related

javascript Call function 10 times with 1 second between

How to call a function 10 times like
for(x=0; x<10; x++) callfunction();
but with 1 sec between each call?
function callNTimes(func, num, delay) {
if (!num) return;
func();
setTimeout(function() { callNTimes(func, num - 1, delay); }, delay);
}
callNTimes(callfunction, 10, 1000);
EDIT: The function basically says: make a call of the passed function, then after a bit, do it again 9 more times.
You can use setInterval for repeated execution with intervals and then clearInterval after 10 invocations:
callfunction();
var callCount = 1;
var repeater = setInterval(function () {
if (callCount < 10) {
callfunction();
callCount += 1;
} else {
clearInterval(repeater);
}
}, 1000);
Added: But if you don't know how long it takes your callfunction to execute and the accurate timings between invocation starting points are not important it seems it's better to use setTimeout for reasons mentioned by Paul S and those described in this article.
Another solution
for(var x=0; x<10; x++) window.setTimeout(callfunction, 1000 * x);
You can try to use setInterval and use a variable to count up to 10. Try this:
var number = 1;
function oneSecond () {
if(number <= 10) {
// execute code here..
number++;
}
};
Now use the setInterval:
setInterval(oneSecond, 1000);
Similar to Amadan's answer but with a different style of closure which means you re-use instead of creating new functions
function call(fn, /* ms */ every, /* int */ times) {
var repeater = function () {
fn();
if (--times) window.setTimeout(repeater, every);
};
repeater(); // start loop
}
// use it
var i = 0;
call(function () {console.log(++i);}, 1e3, 10); // 1e3 is 1 second
// 1 to 10 gets logged over 10 seconds
In this example, if you were to set times to either 0 or Infinity, it would run forever.
I don't know if there's a proper name, but I use a repeater:
function Repeater(callback, delay, count) {
var self = this;
this.timer = setTimeout(function() {self.run();},delay);
this.callback = callback;
this.delay = delay;
this.timesLeft = count;
this.lastCalled = new Date().getTime();
}
Repeater.prototype.run = function() {
var self = this;
this.timesLeft--;
this.callback();
this.lastCalled = new Date().getTime();
if( this.timesLeft > 0) {
this.timer = setTimeout(function() {self.run();},this.delay);
}
}
Repeater.prototype.changeDelay = function(newdelay) {
var self = this;
clearTimeout(this.timer);
this.timer = setTimeout(function() {self.run();},
newdelay-new Date().getTime()+lastcalled);
this.delay = newdelay;
}
Repeater.prototype.changeCount = function(newcount) {
var self = this;
if( this.timesLeft == 0) {
this.timer = setTimeout(function() {self.run();},this.delay);
}
this.timesLeft = newcount;
if( this.timesLeft == 0) clearTimeout(this.timer);
}
You can then use it like this:
new Repeater(callfunction, 1000, 10); // 1 second delay, 10 times
const functionCounterTimer = (callCount) => {
if (callCount < 10) {
setTimeout(() => {
++callCount
console.log("Function Call ", callCount);
functionCounterTimer(callCount);
}, 1000);
}
}
functionCounterTimer(0);
The above was my approach to a similar question.
setInterval(function(){},1000);
Calls the function for every second...
You can also use setTimeout for your thing to work.

Javascript increment not working

Well I did not know what exactly would be a good title for this because it is a most peculiar situation or I'm abnormally dumb.
Here's what im trying to do.
Create a simple <meter> tag which is new in HTML5. The main issue is with my javascript. Im trying to increment the value of the meter tag gradually in my javascript. But somehow it doesn't work the way i want.
JavaScript.
for (var i = 0; i <= 10; i++) {
var a = document.getElementById("mtr1");
setTimeout(function () {
console.log(i);
a.value = i;
}, 250);
}
I'm trying to increase the value of the meter gradually every 250 ms.This doesn't happen. Instead the meter jumps straight to 10.
What interested me was the value of i that i got in the console. I got instances of 10, instead of 1,2,3...10.
Why does this happen?
FIDDLE
It's a JavaScript closures' classic. Here i is an actual reference to the variable, not its copy. After you've iterated through the loop it has the value of 10, that's why all log invocations write 10 to log.
This should work better:
for (var i = 0; i <= 10; i++) {
var a = document.getElementById("mtr1");
setTimeout(function (i) {
return function() {
console.log(i);
a.value = i;
};
}(i), 250 * i);
}
Here the most inner i is the setTimeout's callback argument, not the variable which you've declared in the loop body.
You should read more about closures in JavaScript. When a variable gets closed over, it's the same exact variable, not a copy. Since setTimeout is asynchronous, the whole loop finishes before any of the functions run, therefore the i variable will be 10 everywhere.
DEMO
function incMtrAsync(max, delay, el) {
if (el.value++ < max) {
setTimeout(incMtrAsync.bind(null, max, delay, el), delay);
}
}
incMtrAsync(10, 250, document.getElementById("mtr1"));
The above implementation implements the loop using a recursive approach. Everytime inMtrAsync is called, it checks if the value of the meter reached the max value, and if not, registers another timeout with a callback to itself.
If you want to delay the initial increment as well, just wrap the first call in another timeout.
setTimeout(incMtrAsync.bind(null, 10, 250, document.getElementById("mtr1")), 250);
Nobody used setInterval, so here's my solution ( http://jsfiddle.net/Qh6gb/4/) :
var a = document.getElementById("mtr1");
var i = 0;
var interval = setInterval(function () {
console.log(i);
a.value = ++i;
if (i == 10) {
clearInterval(interval);
}
}, 250);
The problem you describe happens before the asyncronous call to setTimeout in your original version sees a value of 10 for i because that is its value at the moment the callback is executed.
So, this is a problem with the scope of the closure, to make it work you should make it like this:
for (var i = 0; i <= 10; i++) {
var a = document.getElementById("mtr1");
(function (i, a) {
setTimeout(function () {
console.log(i);
a.value = i;
}, 250);
})(i, a);
}
also, since a is always the same, this should be better:
var a = document.getElementById("mtr1");
for (var i = 0; i <= 10; i++) {
(function (i) {
setTimeout(function () {
console.log(i);
a.value = i;
}, 250);
})(i);
}
If then you want to see the counter "ticking up", this will make it visible:
var a = document.getElementById("mtr1");
for (var i = 0; i <= 10; i++) {
(function (i) {
setTimeout(function () {
console.log(i);
a.value = i;
}, 1000 * i);
})(i);
}
See http://jsfiddle.net/LDt4d/
It happens because you called setTimeout, which is "asynchronous". So setTimeout is called 10times but after whole loop is done then it is executed. Therefore, i = 10 in each call...
http://jsfiddle.net/Qh6gb/9/
there is the solution:
var i = 1,
meter = document.getElementById("mtr1");
function increase() {
meter.value = i++;
console.log(i);
if(i<=10) {
setTimeout(increase, 250);
}
}
setTimeout(increase, 250);
you can use timeout jquery plugin:. It is easier
However you should calculate your timeout ,
For you ,timeout=250*max=250*10=2500
So
$('meter').timeout(2500);
Demo
Run for loop inside the function instead of declaring a closure in every step of the loop.
JSFIDDLE: http://jsfiddle.net/Qh6gb/3/
var a = document.getElementById("mtr1");
setTimeout(function () {
for (var i = 0; i < 10; i++) {
console.log(i);
a.value = i;
}
}, 250);
I hope I understand right. Please try and tell me if you got solution.
var count = 0;
function increment(){
document.getElementById("meter").value = count;
count++;
if(count ==10)
count=0;
}
setInterval(increment, 250);
Please check with jsFiddle
You're creating multiple functions that are all being set off at the same time.
Multiply the timer by i for correct delay.
for (var i = 0; i <= 10; i++) {
var a = document.getElementById("mtr1");
setTimeout(function () {
console.log(i);
a.value = i;
}, 250 * i);
}

Trying to figure out why function(argument) not console-logging as expected

var interval = window.setInterval(animate, 500);
var i = 5;
function animate() {
if (i > 1) {
i--;
console.log(i);
} else {
window.clearInterval(interval);
}
}
animate();
The above javascript has var i = 5; and console logs the numbers 5, 4, 3, 2, and 1. DEMO fiddle
I wanted to put the starting number into the animate() function as an argument though, so I added an argument to animate(), defined the variable i as solely var i;, and put a number into animate():
var interval = window.setInterval(animate, 500);
var i;
function animate(i) {
if (i > 1) {
i--;
console.log(i);
} else {
window.clearInterval(interval);
}
}
animate(10);
DEMO fiddle
However, this second attempt only spits out the number 9, and doesn't spit out 10, 9, 8, 7, etc.
Does anyone know what I'm doing wrong?
You could instead have the function recursively call itself, and use setTimeout with an anonymous function that passes in the current value of i.
function animate(i) {
if (i > 1) {
i -= 1;
console.log(i);
setTimeout(function() {
animate(i);
}, 500);
}
}
animate(10);
This way, you don't need to manage an interval, and the animation will only be controlled by the animate() method. Cleaner IMO.
Working fiddle: http://jsfiddle.net/UNkhK/
If you still want control over the timeout: You could also extend this guy's functionality by making him into an object.
function Animation(delay) {
this.delay = delay || 500;
this.timeout = null;
}
Animation.prototype.animate = function(i) {
if (i > 1) {
i -= 1;
console.log(i);
var self = this;
this.timeout = setTimeout(function() {
self.animate(i);
}, this.delay);
}
}
Animation.prototype.stop = function() {
clearTimeout(this.timeout);
}
var animation = new Animation(500);
animation.animate(10);
// Testing
setTimeout(function() {
animation.stop();
console.log('Animation stopped prematurely!');
}, 2000);
Working fiddle / demo: http://jsfiddle.net/5dZyd/
Function arguments are local variables that shadow global variables. So if you use the same name i for the argument, you can't access the global variable that has that name. You need to use different variables.
var global_i;
function animate(local_i) {
if (local_i !== undefined) { // Will be undefined when called from setInterval
global_i = local_i;
}
if (global_i > 1) {
global_i--;
console.log(global_i);
} else {
window.clearInterval(interval);
}
}
animate(10);
you didnt use the variable i, you created a new one, in short, i inside the function definition - animate(i) creates a new var i for the function, and doesn't use the global one try
var i = 10;
function animate() {
if (i > 1) {
i--;
console.log(i);
}
/*
rest of your code here
*/
animate();
see javascript scoping
also use setTimeout not setInterval see here
fiddle
You may try this (call the function from within the function itself and pass the variable i)
var interval;
function animate(i) {
if (i > 1) {
i--;
console.log(i);
interval = setTimeout(function(){ animate(i) }, 500);
}
}
animate(10);
FIDDLE.

creating a timer using setInterval that can clean up after itself?

I want to use setInterval to animate a couple things. First I'd like to be able to specify a series of page elements, and have them set their background color, which will gradually fade out. Once the color returns to normal the timer is no longer necessary.
So I've got
function setFadeColor(nodes) {
var x = 256;
var itvlH = setInterval(function () {
for (i in nodes) {
nodes[i].style.background-color = "rgb(0,"+(--x)+",0);";
}
if (x <= 0) {
// would like to call
clearInterval(itvlH);
// but itvlH isn't in scope...?
}
},50);
}
Further complicating the situation is I'd want to be able to have multiple instances of this going on. I'm thinking maybe I'll push the live interval handlers into an array and clean them up as they "go dead" but how will I know when they do? Only inside the interval closure do I actually know when it has finished.
What would help is if there was a way to get the handle to the interval from within the closure.
Or I could do something like this?
function intRun() {
for (i in nodes) {
nodes[i].style.background-color = "rgb(0,"+(--x)+",0);";
}
if (x <= 0) {
// now I can access an array containing all handles to intervals
// but how do I know which one is ME?
clearInterval(itvlH);
}
}
var handlers = [];
function setFadeColor(nodes) {
var x = 256;
handlers.push(setInterval(intRun,50);
}
Your first example will work fine and dandy ^_^
function setFadeColor(nodes) {
var x = 256;
var itvlH = setInterval(function () {
for (i in nodes) {
nodes[i].style.background-color = "rgb(0,"+(--x)+",0);";
}
if (x <= 0) {
clearInterval(itvlH);
// itvlH IS in scope!
}
},50);
}
Did you test it at all?
I've used code like your first block, and it works fine. Also this jsFiddle works as well.
I think you could use a little trick to store the handler. Make an object first. Then set the handler as a property, and later access the object's property. Like so:
function setFadeColor(nodes) {
var x = 256;
var obj = {};
// store the handler as a property of the object which will be captured in the closure scope
obj.itvlH = setInterval(function () {
for (i in nodes) {
nodes[i].style.background-color = "rgb(0,"+(--x)+",0);";
}
if (x <= 0) {
// would like to call
clearInterval(obj.itvlH);
// but itvlH isn't in scope...?
}
},50);
}
You can write helper function like so:
function createDisposableTimerInterval(closure, delay) {
var cancelToken = {};
var handler = setInterval(function() {
if (cancelToken.cancelled) {
clearInterval(handler);
} else {
closure(cancelToken);
}
}, delay);
return handler;
}
// Example:
var i = 0;
createDisposableTimerInterval(function(token) {
if (i < 10) {
console.log(i++);
} else {
// Don't need that timer anymore
token.cancelled = true;
}
}, 2000);

Create a JavaScript loop without while

I am trying to create a page which needs to preform lots of loops. Using a while/for loops cause the page to hang until the loop completes and it is possible in this case that the loop could be running for hours. I have also tried using setTimeout, but that hits a recursion limit. How do I prevent the page from reaching a recursion limit?
var looper = {
characters: 'abcdefghijklmnopqrstuvwxyz',
current: [0],
target: '',
max: 25,
setHash: function(hash) {
this.target = hash;
this.max = this.characters.length;
},
getString: function() {
string = '';
for (letter in this.current) {
string += this.characters[this.current[letter]];
}
return string;
},
hash: function() {
return Sha1.hash(this.getString());
},
increment: function() {
this.current[0] += 1;
if (this.current[0] > this.max) {
if (this.current.length == 1) {
this.current = [0, 0];
} else {
this.current[1] += 1;
this.current[0] = 0;
}
}
if (this.current[1] > this.max) {
if (this.current.length == 2) {
this.current[2] == 0;
} else {
this.current[3] += 1;
this.current[2] = 0;
}
}
},
loop: function() {
if (this.hash() == this.target) {
alert(this.getString());
} else {
this.increment();
setTimeout(this.loop(), 1);
}
}
}
setInterval is the usual way, but you could also try web workers, which would be a more straightforward refactoring of your code than setInterval but would only work on HTML5 browsers.
http://dev.w3.org/html5/workers/
Your setTimeout is not doing what you think it's doing. Here's what it's doing:
It encounters this statement:
setTimeout(this.loop(), 1);
It evaluates the first argument to setTimeout, this.loop(). It calls loop right there; it does not wait for a millisecond as you likely expected.
It calls setTimeout like this:
setTimeout(undefined, 1);
In theory, anyway. In reality, the second step never completes; it recurses indefinitely. What you need to do is pass a reference to the function rather than the returned value of the function:
setTimeout(this.loop, 1);
However, then this will be window on the next loop, not looper. Bind it, instead:
setTimeout(this.loop.bind(this), 1);
setInterval might work. It calls a function every certain amount of milliseconds.
For Example
myInterval = setInterval(myFunction,5000);
That will call your function (myFunction) every 5 seconds.
why not have a loop checker using setInterval?
var loopWorking = false;
function looper(){
loopWorking = true;
//Do stuff
loopWorking = false;
}
function checkLooper()
{
if(loopWorking == false)
looper();
}
setInterval(checkLooper, 100); //every 100ms or lower. Can reduce down to 1ms
If you want to avoid recursion then don't call this.loop() from inside of this.loop(). Instead use window.setInterval() to call the loop repeatedly.
I had to hand-code continuation passing style in google-code prettify.
Basically I turned
for (var i = 0, n = arr.length; i < n; ++i) {
processItem(i);
}
done();
into
var i = 0, n = arr.length;
function work() {
var t0 = +new Date;
while (i < n) {
processItem(i);
++i;
if (new Date - t0 > 100) {
setTimeout(work, 250);
return;
}
}
done();
}
work();
which doesn't hit any recursion limit since there are no recursive function calls.

Categories