javascript run function with delay inside the iteration - javascript

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.

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 !

How can I call a function after the code in my other function is executed

How can I call a function that will simply display an alert box after the code in the following function is finished executing? Here is the fiddle of the code in action, and now I want to be able to call the additional function below, "isComplete", after the code has completed in the runArray function.
function runArray(arr, fn, delay) {
var index = 0;
var cnt = 0;
var i = 0;
// Called once for each array element
function next() {
if (index >= arr.length) {
return;
}
cnt = +arr[index];
i = 0;
loop();
}
// Represents a single iteration of what was previously a for loop
// Will either schedule the next iteration or move to the next element
function loop() {
if (i < cnt) {
fn(index, i++);
setTimeout(loop, delay); // delay before next iteration
}
else {
++index;
setTimeout(next, delay); // delay before moving to next element
}
}
if (arr.length) {
next();
}
}
function isComplete(){
alert('completed!');
}
Try adding an extra parameter fnComplete and pass it to the function. Then call it before the return statement:
function runArray(arr, fn, delay, fnComplete) {
var index = 0;
var cnt = 0;
var i = 0;
// Called once for each array element
function next() {
if (index >= arr.length) {
fnComplete();
return;
}
Calling the function:
runArray(theArray, theFunction, 100, isComplete);

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

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

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();

Categories