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?
Related
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++) …
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);
}
I have this Javascript/JQuery code:
$.ajax({...}).done(function() {
console.log('done');
});
for(var i = 0; i < 10; i++)
console.log(i);
Let's say the ajax request completes when the loop has reached the 5th iteration, will the browser suspend the loop execution and run the callback or will it wait for the loop to finish?
To make it more clear, is an output like this possible?
0
1
2
3
4
done
5
6
7
8
9
or will the output always be:
0
1
2
3
4
5
6
7
8
9
done
More in general I was wondering if the browser always pushes the callback, when triggered, at the bottom of the execution queue.
You could get both output example you describe, depending on the time the ajax request takes to complete.
EDIT: Note that this might lock your browser for a while, but it should not crash, and then prints something like ***** DONE! ***** 2828725
var promise = new $.Deferred(),
i = 1, j = 0, to = 5000000;
promise.done(function() {
document.write("***** DONE! *****\n" + i);
i = to;
});
setTimeout(function() {
promise.resolve();
}, 1000);
for(i = 1; i < to; ++i) {
console.log(++j);
//alert(++j);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
The test I did seems to show the loop must complete first
fiddle
time = new Date()
new Request.JSONP({
url: 'http://jsfiddle.net/echo/jsonp/',
onSuccess: function (response) {
console.log('done ' + (new Date()-time))
}
}).send();
for (var i = 0; i <= 65535; i++) {
for (var j = 0; j <= 10000; j++) {
if (i===65535 && j == 10000)
{
console.log('loop complete ' + (new Date()-time))
}
}
}
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.
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