Set a delay (timeout) inside a double (nested) loop - javascript

Completely stuck.
I have seen this popular solution for adding delays between iterations of a loop (https://stackoverflow.com/a/3583740), but it only seems to work for a single loop (i.e not nested).
This is the pseudo code,
for (var i = 0; i < max; i++){
for (var j = 0; j < max; j++){
pause(1000); // ideally would just elegantly pause all execution
}
}
I am trying to use setTimeout (unless other options exist!) but I can't seem to wrap my head around how to set it up.
Context - It should pause long enough for an animation to occur. (A different animation occurs depending on the values of i and j ).

As it has been said, you can't really pause execution in javascript. Though a trick could be to collect the instructions in a delayed queue which executes itself fifo. E.g.:
// helper function
var delayed = (function() {
var queue = [];
function processQueue() {
if (queue.length > 0) {
setTimeout(function () {
queue.shift().cb();
processQueue();
}, queue[0].delay);
}
}
return function delayed(delay, cb) {
queue.push({ delay: delay, cb: cb });
if (queue.length === 1) {
processQueue();
}
};
}());
your example, rewritten:
var i = 0, j, max = 3;
for (; i < max; i += 1) {
for (j = 0; j < max; j += 1) {
// add function to the queue, shadowing i/j with an IIFE:
delayed(1000, function(i, j) {
return function() {
console.log(i, j);
};
}(i, j));
}
}
demo: http://jsbin.com/kadepage/1/

This will work as nested for loop with delay.
var i = o = 0;
var max = 10;
var delay = 1000;
function rec()
{
console.log("outerloop"+o);
var inner = setInterval(function(){
console.log("innerloop"+i);
console.log(new Date());
i++;
if(i==max)
{
clearTimeout(inner);
var outer = setTimeout(function(){
o++;
i=0;
if(o==max)
{
return;
}
clearTimeout(outer);
rec();
},delay);
}
},delay);
}
rec();

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

setTimeout only runs once when i use it inside a for loop

im trying to bubble sort some information (by asking users which they prefer instead of compare)
when i use settimeout in callback function it only runs once at the first level of for loop.
(s changes by clicking on images
this is the main function we pass it an array as argument
function bubble_Sort(a)
{
var swapp;
var n = a.length-1;
var x=a;
do {
swapp = false;
for (var i=0; i < n; i++)
{
s=0;
limage.setAttribute('src','images/'+x[i]+'.jpg');
rimage.setAttribute('src','images/'+x[i+1]+'.jpg');
console.log('images changed');
check(i,function(){
if (s==0)
{
var temp = x[i];
x[i] = x[i+1];
x[i+1] = temp;
swapp = true;
}
});
}
n--;
} while (swapp);
return x;
}
and here is check function (callback to wait for user to click on one of images)
var check=function(p,callback){
setTimeout(function(){console.log('this is Timeout');},3000);
callback();
}
you don't need a set-timeout function to implement such functionality, your code has to wait for a click (asynchronous) event to continue it's computation. can get what you want with the help of generator functions.
here's a simple working sample, the code is mostly self descriptive, hope it helps!
// a generator function
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield
function* bubbleSort(items) {
var length = items.length;
for (var i = 0; i < length; i++) {
for (var j = 0; j < (length - i - 1); j++) {
firstImageIndex = j;
secondImageIndex = j + 1;
updateUI(); //magic happens here
shouldBeSwapped = yield i; // wait for user to select a picture (no set timeout here)
if (shouldBeSwapped) {
let tmp = items[j];
items[j] = items[j + 1];
items[j + 1] = tmp;
}
}
}
updateUI(); // final update
}
Codepen Link Here !

javascript run function with delay inside the iteration

I want to find elements with javascript with delay. In first step I made this and it works.
function mytag() {
var elements = document.getElementsByTagName('div');
for (var i=0, im=elements.length; im>i; i++) {
if (elements[i].className ==='hi'){
alert('found');
}}
}
In the second step, I made some changes to code to put delay between iteration. I followed this link but cannot make it to work . Whats wrong?
function mytag() {
var elements = document.getElementsByTagName('div');
for (var i=0, im=elements.length; im>i; i++) {
(function(i){
setTimeout(function(){
if (elements[i].className ==='hi'){
alert('found!');
}
}, 3000 * i);
}(i));
}
}
Here's an example of how you could add asynchronousity into your lookup function:
function findElements() {
var elements = document.getElementsByTagName('div');
var index = 0;
var findNext = function() {
var element = elements[index];
index++;
if (element.className === 'hi'){
// Item found
console.log('found:'+element);
}
if (index < elements.length) {
setTimeout(findNext, 100);
}
};
findNext();
}
findElements();
http://jsbin.com/zeseguribo/1/edit?html,js,console
function sleep(milliseconds) {
var start = new Date().getTime();
while (1) {
if ((new Date().getTime() - start) > milliseconds) {
break;
}
}
} // sleep end
then call sleep(3000) in your loop.
Edit: This is a blocking way of delay. For async, non-blocking delay, you may use a recursive function.

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

Can't call a function through setTimeout

I'm trying to make a few functions to work one after the other with a waiting time of 1.5 seconds between them.
NOW, when i try doing so with the same Id (Inside the "NoteList(>here<)", like 1, 2, 3, or any other, it works;
for (var i = 0; i < 36; i++)
{
setTimeout(function () { OnClcRandom(NoteList[0]) }, i * 1000 + 1000);
}
BUT! when i try doing so with the var i, it doesn't work and gets the all of the functions in the page stuck. any idea why?
for (var i = 0; i < 36; i++)
{
setTimeout(function () { OnClcRandom(NoteList[i]) }, i * 1000 + 1000);
}
That would be because all of the functions refer to the same live i variable, not the value of the variable at the time you called setTimeout(). Which means by the time the timeouts actually run your function i will be 36.
Try this instead:
for (var i = 0; i < 36; i++) {
(function(x){
setTimeout(function () { OnClcRandom(NoteList[x]) }, i * 1000 + 1000);
)(i);
}
This executes an anonymous function on each iteration of the loop, with each execution getting its own x parameter for use in your original function.
Javascript doesn't create local scope for block. :)
And in your second example var i equal 36 (last value).
You need create local scope inside loop.
for (var i = 0; i < 36; i++) {
(function (i) {
setTimeout(.......);
}(i))
}
You also may fixed 'i' value assign it to function property:
for (var i = 0, f; i < 36; i++){
f = function _callback() { var i = _callback.i; .....};
f.i = i;
setTimeout(f, i * 1000);
}

Categories