javascript changing global var setTimeout - javascript

I Want to make a loop to live 2 seconds, then brake after.
This code wont work, the loop goes to end, it wont brake at 2 seconds. Why?
var stop = 0;
setTimeout(function() {
stop = 1;
}, 2000);
for (var i = 0; i < 10000; i++) {
console.log("wait" + stop);
if (stop == 1) break;
}
Is there a workarround?

A setTimeout callback will never interrupt a running synchronous loop. To achieve the desired result, you can change your loop head to
for (var i=0, timeout=Date.now()+2000; i<10000 && Date.now()<timeout; i++) …

Related

Conditional Statements Array Looping

I'm trying to create an image slider for a website, I want to learn why my array won't go back to zero after finishing the first iteration and keep on iterating. I want the slider to iterate on and on automatically.
function run() {
for (let i = 0; i < imgArray.length; i++) {
(function(e) {
setTimeout(function() {
if (i == imgArray.length) {
i = 0;
}
imgContainer.style.background = imgArray[i];
}, 3000 * e);
})(i);
};
imgContainer.style.height = '100vh';
}
The condition i == imgArray.length inside the loop is never true, since the loop runs until i < imgArray.length. You could use <= instead as Ali Abug Hijleh suggested, but I think it would be easier to maintain if you explicitly show the loop should run forever with while (true) and use the % operator to get the right index:
function run() {
let i = 0;
while (true) {
(function(e) {
setTimeout(function() {
imgContainer.style.background = imgArray[i % imgArray.length];
}, 3000 * e);
})(i);
};
imgContainer.style.height = '100vh';
++i;
}
i will never reach the imgArray.length because the loop only works when i is less than imgArray.length (since you use i < imgArray.length as the condition)
Try if (i == imgArray.length -1) { ... } instead.
That's because your for loop ends before you reset it to zero because you reset it to zero inside a setTimeout

Calling clearInterval in Browser Console on Chrome

I am running this JS code in my Browser Console to display some names from a table in an interval of 4 seconds. After the loop has run X amount of times, it should clear the interval.
$(document).ready(function() {
for(var j = 0; j < 2; j++) {
var refreshIntervalId = setInterval(function(){var td = $("tr td:first-child");
for (var i = 6; i < 26; i++){
console.log(td[i].innerText);
}},4000);
$("#idc4").click();
}
clearInterval(refreshIntervalId);
});
I've saved the interval ID in the variable refreshIntervalId and I am calling the clearInterval function after the loop with this ID, but my interval keeps running, displaying the same names in the console. Is the variable out of scope? Or does the browser console have some limitations when it comes to this?
You need your intervals to stop themselves after they've been called X times.
So you'll need to change your code's logic a little. Because right now, your for loop combined with the use of var will replace your intervalId each time you loop.
I introduced an intervalContext object that contains the intervalId and the number of times it was called. By binding it to the interval, each interval has its own intervalContext.
// how many times will the interval be called :
var numberOfCalls = 3;
for (var j = 0; j < 2; j++) {
// initiating a new intervalContext
var intervalContext = {};
intervalContext.called = 0;
// storing the intervalId in the intervalContext so the interval can clear itself
intervalContext.intervalId = setInterval((function() {
// the intervalContext object will be referenced by 'this'
this.called++;
for (var i = 6; i < 26; i++) {
console.log("looping i = " + i);
}
if (this.called > numberOfCalls) {
console.log("Interval cleared. ID=", this.intervalId);
clearInterval(this.intervalId);
}
}).bind(intervalContext), 1000); // binding the interval to the intervalContext
console.log("Interval started. ID=" + intervalContext.intervalId);
}

Can multiple lines of code execute at a random time in Javascript?

So I just wonder, if I have something like this:
var arr = [4,3,2,2]
setTimeout(function() {
arr.push(3)
}, 2) // 2 MS
for (var i = 0; i < arr.length; i++) {
arr.splice(i, 1)
arr.push(Math.floor(Math.random() * 7) + 2)
}
Is it possible that the timeout can execute anytime under the time of the loop, depending on how fast the JS is executed, or does the timeout wait for the loop to end or something?

setTimeout() in cycle, strange behaviour

guys! I am a total newbie in javascript. I wrote my first program and already stuck with it's behavior:
var elements = document.getElementsByTagName("img");
for (var i = 0; i < elements.length; i++) {
if (i % 2 == 0) {
elements[i].src = "img.jpg";
for (var j = 0; j <= 1; j += 0.1) {
setTimeout(increase_opacity(elements[i], j), 2000);
// setTimeout(alert(j), 2000);
}
}
}
function increase_opacity(element, opacity) {
element.style.opacity = opacity;
}
I can not see that opacity changes, but under debugger it does, so setTimeout just doesn't work. If I uncomment // setTimeout(alert(j), 2000); I can see both opacity change and alert message on every cycle step. Why is that?
setTimeOut accepts a function, and what you were doing is passing it the result of a call to increase_opacity. Code below should work for you. Notice how increase_opacity is wrapped inside of the anonymous function definition.
var elements = document.getElementsByTagName("img");
for (var i = 0; i < elements.length; i++) {
if (i % 2 == 0) {
elements[i].src = "img.jpg";
for (var j = 0; j <= 1; j += 0.1) {
(function(element, opacity) {
setTimeout(function() { increase_opacity(element, opacity) } , 2000);
})(elements[i], j);
// setTimeout(alert(j), 2000);
}
}
}
Here is the doc on setTimeOut http://www.w3schools.com/jsref/met_win_settimeout.asp
You need to pass a function to setTimeout(). What you are doing is calling increase_opacity immediately and then passing the return value to setTimeout().
Since you want to call the function with particular arguments, you can use a closure to record the current values of i and j:
setTimeout((function(a, b) {
return function() {
increase_opacity(a, b);
};
})(elements[i], j), 2000);
Are you aware that setTimeout() is not a blocking call? Your script does not stop at the setTimeout() function, but continues its execution. So here's what's happening here:
1) Your code starts the loop;
2) When it enters a setTimeout(), it launches the timer it and goes ahead;
3) Repeat step 2 for every element; (Please note that steps 2 and 3 are executed in a few ms)
4) All the timers expires, all the instructions are executed all at once.
To avoid this, you should write something like:
var elements = document.getElementsByTagName("img");
for (var i = 0; i < elements.length; i++) {
if (i % 2 == 0) {
elements[i].src = "img.jpg";
setTimeout(function(){increase_opacity(elements[i],0);}, 2000);
}
}
function increase_opacity(element, opacity) {
element.style.opacity = opacity;
if (opacity < 1) setTimeout(function(){increase_opacity(element, opacity+0.1);},2000);
}
NB: When dealing with setTimeout() you should avoid that notation when calling function with parameters. You should always use this:
setTimeout(function(){yourFunctionName(arg1, arg2, arg3);});
NB 2: setTimeout(alert(j),2000); is not even waiting 2 seconds to appear. Like I said above, you should use the anonymous function when dealing with setTimeout(). It's probably giving the impression it's working because of this, but it's a sort of glitch IMO.

Let for loop wait until code finish execution javascript

I have a bubble sort function that when the a swap occurs it should show it visibly. But after lots of approaches it continues executing the loops without waiting for the animation to stop. (we are only allowed to use JavaScript). Is there a way to tell the website to wait for the animation to complete. Here is a snippet of my code:
for (var i = 0; i < len; i++)
{
for (var j = 0, swapping, endIndex = len - i; j < endIndex; j++)
{
if (marksArr[j] > marksArr[j + 1])
{
//swap objects
/*(function() {
var k = 0,
action = function() {
document.getElementById(coursesKey[j]).style.top = (parseInt(document.getElementById(coursesKey[j]).style.top) + 1) + 'px';
document.getElementById(coursesKey[j + 1]).style.top = (parseInt(document.getElementById(coursesKey[j+1]).style.top) - 1) + 'px';
k++;
if (k < difMoves) {
setTimeout(action, 200);
}
};
setTimeout(action, 200);
})();*/
}
}
}
As #cookie monster already explained, you can't block loops in JavaScript and update the UI using setTimeout() at the same time (this is because JavaScript is essentially single-threaded).
The most elegant solution would be "recording" each animation step while the for loops process the array, and then run the animation afterwards, e.g. using setTimeout(). Some time ago, I've implemented this approach for a similar question on StackOverflow; here's a demo: JSFiddle
The code can also be simplified:
function swap(list, i1, i2) {
var tmp = list[i1];
list[i1] = list[i2];
list[i2] = tmp;
}
function animateBubblesort(list) {
var animationSteps = [];
// Sort array
for (var n = list.length; n > 1; --n) {
for (var i = 0; i < n-1; ++i) {
if (list[i] > list[i+1]) {
swap(list, i, i+1);
// Add new step (clone of current array) to "animation queue"
animationSteps.push(list.slice(0));
}
}
}
// Print animated steps (using setInterval() for simplicity)
var count = 0,
interval = setInterval(function(){
console.log(animationSteps[count]);
if (++count >= animationSteps.length) {
clearInterval(interval);
}
}, 250);
}
animateBubblesort([5,8,2,4,1,9,7,3,0,6]);
DEMO
Another (less intuitive) possibility would be to implement the algorithm without loops in order to get control over when the next step of the algorithm is executed (so you have time for your animation). Here's an example: DEMO 2

Categories