How to use setInterval() inside for loop - javascript

Please find my code below.
for (i= 0; i < region.length; i++) {
point = region[i];
animation = setInterval(function () {
..........
}, 12);
}
I want to execute the codes in setInterval before i value changes from 0 to 1. But currently after all the execution of for loop only, codes in the setInterval method is getting executed. is there any way to achieve my requirement.

Use closure inside for loop:
(function(i) {
setInterval(function() {
console.log("inside setinterval" + i)
}, 10);
})(i)
hope this solves your problem

Async loop you need:
var len = region.length;
var i = 0;
var animate = function(){
setTimeout(function () {
point = region[i];
//do something..........
if (i++ < len) animate();
}, 12);
};

You should use recursion for such requirements. Also, you should use setTimeout as setInterval will run for eternity(till page exists) until you clear it.
var i = 0;
var MAX_COUNT = 10;
function doSomething(str){
console.log(str);
processData();
}
function initSetTimeout(callback){
setTimeout(callback, 1000)
}
function processData(){
if(++i<MAX_COUNT)
initSetTimeout(doSomething.bind(null, i))
}
processData()

Related

Is there any way to pause a for loop until a variable is true

Is there a way to pause a for loop until a variable is true? For example, if I had this code,
var flag = false;
for(var i = 0; i < 15; i++){
console.log(i);
}
and i was equal to 7, could I pause the loop until flag = true?
Thanks!
JavaScript is a single-thread event-based model: if you could pause the execution you couldn't evaluate your flag during that time.
Also, if the value of the flag depends on an user event, you want to wait for the event to fire and not for the variable to change.
If, like in your example, you know beforehand when you want to pause the loop, you should split it:
for(var i = 0; i <= 7; i++){
console.log(i);
}
document.querySelector("button").onclick = function() {
for(var i = 8; i < 15; i++){
console.log(i);
}
}
If you don't know it (because it is decided inside the for loop) you just need to ensure that the next time the loop starts in the point it stopped (e.g., by reusing the i variable).
for (var i = 0; i < 15; i++) {
console.log(i);
if (Math.random() < 0.2) { break; }
}
document.querySelector("button").onclick = function() {
for (i++; i < 15; i++) {
console.log(i);
}
}
If the code inside the loop is long you can wrap it inside a function (thanks #tom):
function logIndex() {
//some code
console.log(i);
}
Actually, you can isolate all the logic to manage the loop and the user event in a single function that, recursively, creates a handler for the user event to call itself. It has also the advantage that you can stop the loop as many times as needed.
var button = document.querySelector("button");
function logIndexes(index) {
for (index; index < 15; index++) {
console.log(index);
if (Math.random() <= 0.2) {
return button.onclick = function() {
logIndexes(index + 1);
}
}
}
button.onclick = null;
}
logIndexes(0);
<button>Click me!</button>
You could use an interval an a timeout for simulating a loop and for changing the flag.
function count(start, end, inc) {
var i = start;
return function () {
if (i === 8 && ! flag) {
return;
}
console.log(i);
i += inc;
if (i >= end) {
clearInterval(interval);
}
}
}
var flag = false,
interval = setInterval(count(0, 10, 1), 500);
setTimeout(function () {
flag = true;
}, 10000);
.as-console-wrapper { max-height: 100% !important; top: 0; }
No. A loop will execute until a condition is true.
Try this
var flag = false;
for(var i = 0; i < 15; i++){
If ((i > 6) && (! flag)){
i = 6;
} else {
console.log(i);
}
}
This will made an infinite loop, but I think you know how & where flag will be true, may be the syntax is not true, but I give you the idea of how to pause a loop...
ES6 has something called generators which may be helpful to you. It's not a for loop but could "pause" your script.
Read more here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators
function* idMaker() {
let index = 0;
while (index < 15) {
yield index++;
}
}
var gen = idMaker();
//console.log(gen.next().value);
//console.log(gen.next().value);
for (i of gen) {
if (gen.next().done) {
console.log('all done');
} else {
console.log(i);
}
}

How define a couple of setIntervals and clear them with delay

I need to randomly change characters of a text and after some delay fix them.
There is my code:
<h1 id="text" style="margin-top:100px;">SOME TEXT</h1>
<script>
var text = document.getElementById("text").innerHTML.split("");
var myArr = text;
for (i = 0; i < myArr.length; ++i) {
var handle = setInterval(function () { xyz(i) }, 100);
setTimeout(function (handle) {
myArr[i] = text[i];
clearInterval(handle);
}, (i) * 1000);
}
function xyz(index) {
myArr[index] = String.fromCharCode(Math.random() * 26 + 65);
document.getElementById("text").innerHTML = myArr;
}
</script>
It seems i have no a good understanding of how setInterval work! :(
EDIT:
With my code only text[text.length+1] character has change that mean passed parameter to xyx() function is last value of loop counter variable (after loop over). Now my question is how trigger setInterval() function with i = 0 ,1 ... , text.length.
Can someone guide me?
basicly setInterval execute a function with a iteration in time. and setInterval gives you a promise to cancel it any time you want.
var myPromise = setInterval(function(){
//some code here
},delayMiliseconds);
to cancel this code
clearInterval(myPromise);
Related to this question problem was wrong way to passing arguments to setInterval().the callback function i passed to setInterval() maintains a reference to "i" rather than the snapshot value of "i" as it existed during each particular iteration...
<h1 id="text" style="margin-top:100px;">SOME TEXT</h1>
<script>
var text = document.getElementById("text").innerHTML.split("");
var myArr = document.getElementById("text").innerHTML.split("");
for (i = 0; i < text.length; i++) {
var handle = setInterval(function (k) { xyz(k) }, 100,i);
setTimeout(function (handle, i) {
console.log(i);
console.log(text[i]);
myArr[i] = text[i];
clearInterval(handle);
}, (i) * 1000,handle,i);
}
function xyz(index) {
myArr[index] = String.fromCharCode(Math.random() * 26 + 65);
document.getElementById("text").innerHTML = myArr.toString();
}
</script>

Image not changing

Hi I am trying to get an image to blink using the code below by changing the image. Is there something wrong with my "setTimeout"? TIA
var Test = new Array();
Test.length = 2;
for (var i = 0; i < Test.length; i++) {
Test[i] = new Image();
Test[i].src = "images/Image2" + (i+1) + ".png";
}
function ChangeImage() {
for (var i = 0; i < Test.length; i++) {
document.getElementById('Test_Image').src = Test[i].src;
}
setTimeout("ChangeImage()", 1000);
}
ChangeImage();
First.. you complicated yourself with the new Image() part. You could just use Test[i] = "images/Image2" + (i+1) + ".png";
And for your code, firstly you change the images really fast once every 1 second.
It should be something like this:
function ChangeImage() {
for (var i = 0; i < Test.length; i++) {
setTimeout(function(){document.getElementById('Test_Image').src = Test[i];
}, (i+1) *1000);
}
if(play){
setTimeout("ChangeImage()", Test.length * 1000);
}
}
This will not halt the javascript code at any point.
After 1 sec it will put image21, after 2 seconds image21 and it will call itself again and it will start all over again;
I put the variable play so you could stop the animation if you wanted.
setTimeout() is not blocking. That means it only schedules an activity to happen some time in the future and the rest of your Javascript just keeps running. So, you were scheduling Test.length setTimeout() all for the exact same time 1 second from now. Instead, you need to schedule the next image change and then, when that timer fires, you schedule the one after that and so on.
If you just want to cycle through the various images one second apart, you can do this:
function ChangeImage() {
var cntr = 0;
function next() {
if (cntr < Test.length) {
document.getElementById('Test_Image').src = Test[cntr++].src;
// after changing src, schedule next change for 1 second from now
setTimeout(next, 1000);
}
}
// start first iteration
next();
}
ChangeImage();
You may also need to make sure that all your images are properly preloaded so they display immediately when you set their source. There are numerous ways to make sure the preload is done before starting the rotation such as these:
Image preloader javascript that supports events
How do you cache an image in Javascript
Try something like this.
Edit: Accidentally put setTimeout instead of setInterval. Thanks Santi for point that out.
var Test = new Array();
Test.length = 2;
for (var i = 0; i < Test.length; i++) {
Test[i] = new Image();
Test[i].src = "images/Image2" + (i+1) + ".png";
}
var count = 0;
function ChangeImage() {
if (count >= Test.length)
count = 0;
document.getElementById('Test_Image').src = Test[count].src;
count++;
}
setInterval(ChangeImage, 1000);
Your for loop switches the src once and immediately switches it back, so you can't see it change. Try this instead:
var Test = [];
for (var i = 0; i < 2; i++) {
Test.push("images/Image2" + (i+1) + ".png");
};
var x = 0;
document.getElementById('Test_Image').src = Test[x];
(function ChangeImage() {
if(++x >= Test.length) x = 0;
document.getElementById('Test_Image').src = Test[x];
setTimeout(ChangeImage, 1000);
})();
EDIT: As Santi pointed out, my original solution only supported two images, while OP requested to loop through an array.

how to use javascript cleanTime in such case?

I need to clear the timeout and I couldn't figure how. I'm not sure what to pass on the clearTimeout method from window object... any tips?
for (var k = 0; k <= arr2.length; k++) {
(function (k) {
window.setTimeout(function () {
//do something
}, 6000 * k);
})(k);
}
Since you are creating arr2.length amount of timers, if you need "kill" a specific timer, you need an array of references.
//create a reference storage
var timerRefs = [];
for (var k = 0; k <= arr2.length; k++) {
(function (k) {
//reference the timeout to a variable
var ref = window.setTimeout(function () {
//do something
}, 6000 * k);
//store that reference in the array
timerRefs.push(ref);
})(k);
}
to clear a specific one, do:
clearTimeout(timerRefs[N]); //where N is the index of that timer
If you want to make a timeout cancellable, you MUST capture its return value.
var myTimer = setTimeout(...);
Then, just pass that value to the function:
clearTimeout(myTimer);
Personally I would rewrite that:
(function(inp) {
var k = 0, l = inp.length, timer;
timer = setInterval(function() {
// do something with inp[k];
k++;
if( k > l) clearInterval(timer);
},6000);
})(arr2);
Some browser (Firefox in particular) react poorly to having too many timeouts running at once.

setTimeout inside for loop [duplicate]

This question already has answers here:
setTimeout in for-loop does not print consecutive values [duplicate]
(10 answers)
Closed 7 years ago.
I want a string to appear character-for-character with the following code:
function initText()
{
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
for(c = 0; c < text.length; c++)
{
setTimeout('textScroller.innerHTML += text[c]', 1000);
}
}
window.onload = initText;
It's not working.. what am I doing wrong?
Try something like this:
function initText()
{
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
var c = 0;
var interval = setInterval(function() {
textScroller.innerHTML += text[c];
c++;
if(c >= text.length) clearInterval(interval);
}, 1000);
}
Note I added clearInterval to stop it when it's needed.
Currently, you are defining 18 timeouts and all will be executed ~ at once.
Second problem is, you pass instructions to execute as a String. In that case, the code won't have access to all variables defined in initText, because evaluated code will be executed in global scope.
IMO, this should do the job
function initText(){
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
var c = 0;
(function(){
textScroller.innerHTML += text.charAt(c++);
if(text.length > c){
setTimeout(arguments.callee, 1000);
}
})();
}
Even more generic than answer by #yauhen-yakimovich:
Using Timeout:
var repeat = (function () {
return function repeat(cbWhileNotTrue, period) {
/// <summary>Continuously repeats callback after a period has passed, until the callback triggers a stop by returning true. Note each repetition only fires after the callback has completed. Identifier returned is an object, prematurely stop like `timer = repeat(...); clearTimeout(timer.t);`</summary>
var timer = {}, fn = function () {
if (true === cbWhileNotTrue()) {
return clearTimeout(timer.t); // no more repeat
}
timer.t = setTimeout(fn, period || 1000);
};
fn(); // engage
return timer; // and expose stopper object
};
})();
Using Interval:
var loop = (function () {
return function loop(cbWhileNotTrue, period) {
/// <summary>Continuously performs a callback once every period, until the callback triggers a stop by returning true. Note that regardless of how long the callback takes, it will be triggered once per period.</summary>
var timer = setInterval(function () {
if (true === cbWhileNotTrue()) clearInterval(timer);
}, period || 1000);
return timer; // expose stopper
};
})();
Slight difference between the two indicated in comments -- the repeat method only repeats after the callback performs, so if you have a "slow" callback it won't run every delay ms, but repeats after every delay between executions, whereas the loop method will fire the callback every delay ms. To prematurely stop, repeat uses an object as the returned identifier, so use clearTimeout(timer.t) instead.
Usage:
Just like answer by #soufiane-hassou:
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
var c = 0;
var interval = repeat/* or loop */(function() {
textScroller.innerHTML += text[c];
c++;
return (c >= text.length);
}, 1000);
As mentioned, premature stopping would be:
/* if repeat */ clearTimeout(interval.t);
/* if loop */ clearInterval(interval);
Try this:
function initText()
{
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
for(c = 0; c < text.length; c++)
{
setTimeout("textScroller.innerHTML += '" + text[c] + "'", 1000 + c*200);
}
}
window.onload = initText;
Try using a closure:
function init() {
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
var c = 0;
function run() {
textScroller.innerHTML += text[c++];
if (c<text.length)
setTimeout(run, 1000);
}
setTimeout(run, 1000);
}
init()
The problem in your code is that the code you put in the string will run in the global context, where textScroller is not defined (it is defined inside your function).
I want to share a snippet (based on answer by Soufiane Hassou). It extends to the case when you literally replace a for-loop body to be iterated over some array in a fixed interval of time. Basically same synchronous loop but with "sleep" pausing (because javascript is not a synchronous programming language).
function loop(arr, take, period) {
period = period || 1000;
var i = 0;
var interval = setInterval(function() {
take(i, arr[i]);
if (++i >= arr.length) { clearInterval(interval);}
}, period);
}
Usage example:
loop([1, 2, 3, 4], function(index, elem){
console.log('arr[' + index + ']: ' + elem);
});
Tested in Node JS. Hope that helps someone.
edit>
the following update makes code usable together with libs doing heavy "prototyping" (like jQuery or prototype):
function loop(arr, take, period) {
period = period || 1000;
var scope = {
i: 0,
arr: arr,
take: take,
};
var iterate = (function iterate() {
if (this.i >= this.arr.length) { clearInterval(this.interval); return}
take(this.i, this.arr[this.i++]);
}).bind(scope);
scope.interval = setInterval(iterate, period);
}
Your for loop is setting a timeout for every character at once, so they will not appear in sequence, but all at once. Your setTimeout should include code to another setTimeout that will include the next character to display.
So something like this (didn't test this)
function initText()
{
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
setTimeout('nextChar(text)', 1000);
}
function nextChar(text){
if(text.length > 0){
textScroller.innerHTML += text[0];
setTimeout('nextChar(text.substring(1))', 1000);
}
}
If you want to preserve setTimeOut (instead of setInterval) and use named function (instead of evaluating code block in setTimeOut call), then this could be helpful:
var b = {
textScroller: document.getElementById('textScroller'),
text: "Hello how are you?"
};
function initText() {
for(c = 0; c < b.text.length; c++) {
setTimeout("append("+c+")", 1000 + c*200);
}
}
function append(c) {
b.textScroller.innerHTML += b.text[c];
}
window.onload = initText;
With the above you can pass a parameter to append function.
To pass several parameters the next code does the trick:
var glo = [];
function initText()
{
var textScroller = document.getElementById('textScroller');
var text = "Hello how are you?";
var timeout_time;
for(c = 0; c < text.length; c++) {
glo[glo.length] = {text:text, c:c, textScroller:textScroller};
timeout_time = 1000 + c * 200;
setTimeout("append(" + (glo.length - 1) + ")", timeout_time);
}
}
function append(i)
{
var obj = glo[i];
obj.textScroller.innerHTML += obj.text[obj.c];
obj = null;
glo[i] = null;
}
window.onload = initText;
With the above you have only one global array glo. In loop you create new array members to glo and in append() function refer to these members using index which is passed as parameter.
CAUTION: the second code sample is not meant as best or most suitable solution to OP:s problem, but may benefit in other setTimeOut relative problems, eg. when someone wants to make a presentation or performance test where some functionalities are needed to call after some delay. The advantage of this code is to make use of for loops (many coders want to use for loops) and the possibility to use also inner loops and the ability to "send" local variables in their loop time state to timeOut functions.
May be better to loop in cascade. For exemple to fade a div :
div=document.createElement('div');
div.style.opacity=1;
setTimeout(function(){fade(1);},3000);
function fade(op){
op-=.05;
if(op>0) setTimeout(function(){div.style.opacity=op;fade(op);},30);
else document.body.removeChild(div);
}

Categories

Resources