Is there any method to sleep in javascript in a loop? - javascript

For example, there is for loop that I want to sleep for some seconds.
$.each(para.res, function (index, item) {
Sleep(100);
});
I know I can use setTimeout or setInterval but both of them are asychronous, the loop will continue, just the function in the setTimeout will run in a few seconds if I do it this way.
$.each(para.res, function (index, item) {
setTimeOut(function(){do something},1000);
});

You can define a function.
var i = 0;
function recursive() {
setTimeout(function(){
var item = para.res[i];
// do something
i++;
if (i < para.res.length) recursive()
}, 100)
}

No, there is no built in method for that. You could use a busy loop, but that will freeze the browser in the mean time, and you can't do it for too long because then the browser will stop the script.
If you want the different pieces of code spread out over time, just set different times for setTimeout:
$.each(para.res, function (index, item) {
setTimeOut(function(){do something},1000 * index);
});
This will start the code for the first item after one second, the code for the second item after two seconds, and so on.
Or use setInterval:
var index = 0, timer = setInterval(function(){
if (index < para.res.length) {
var item = para.res[index];
// do something
index++;
} else {
clearInterval(timer);
}
}, 1000);

Related

Javascript function setTimeout and setIntervall not working

I've got this Problem here, that this function is not working and I cant figure out why..
This function should count to 10 (in 10 seconds). For this purpose I'm using a for loop with setTimeout function - duration set to 1000ms.
It should go on and on for what i took the setInterval function.
function timer() {
var time=10;
for(i=0; i<time; i++){
setTimeout(console.log(i+1), 1000);
}
}
setInterval(timer, 10000);
The Problem is, that it isnt working and I dont understand why ... I have found another working solution but would like to know the issue of this one. :)
The reason that nothing appears to happen is the way that you use setTimeout. Instead of providing an event handler you are calling console.log and try to use the return value from that call as event handler.
The closest thing that would at least do something would be to make a function that calls console.log:
setTimeout(function(){ console.log(i+1) }, 1000);
However, you will notice that it will just log the value 11 ten times at once, every ten seconds, indefinitely.
Eventhough the loop counts from 0 to 9, you start a timeout in each iteration that will be triggered one second from when it was created. As all ten timeouts are created at the same time, they will be triggered at the same time. There isn't a separate variable i for each handler, so they will all show the value in the variable at the time that they are triggered, and as the loop has completed before any of them can be called they will all show the final value 10 + 1.
You are using both an interval and timeouts, you should use one or the other.
You can start timeouts in a loop, but then you should only do it once, not in an interval, and you should specify the time from start to when you want it to be triggered:
var time = 10;
for (var i = 1; i <= time; i++){
setTimeout(function() { console.log('tick'); }, 1000 * i);
}
If you want to use the variable in the event handler, then you need to create a copy of the variable for each iteration:
var time = 10;
for (var i = 1; i <= time; i++){
(function(copy){
setTimeout(function() { console.log(copy); }, 1000 * i);
})(i);
}
You can use an interval, but then you don't have a loop, it's the interval that is the loop. Use clearInterval to stop it when you reach the end of the loop:
var i = 1, time = 10, handle;
function timer() {
console.log(i);
i++;
if (i > time) clearInterval(handle);
}
handle = setInterval(timer, 1000);
First, it's not working because setTimeout call is wrong. Even if your setTimeout call worked, there's another issue here. Your code will actually print 11 every 10 seconds.
function timer() {
var time = 10;
for (i = 0; i < time; i++) {
setTimeout(function() {
console.log(i + 1)
}, 1000);
}
}
setInterval(timer, 10000);
Because, you have sequential setTimeout calls to be effected every second and you are forming a closure on the variable i.
You need to take care of the closure and calls must be done after the second has been printed.
function timer() {
var p = Promise.resolve();
for (var i = 0; i < 10; i++) {
p = p.then(closure(i));
}
}
function closure(i) {
return (function () {
return new Promise(function (resolve) {
setTimeout(function () {
document.getElementById('results').innerHTML = (i + 1) + '\n';
resolve();
}, 1000);
})
});
}
timer();
setInterval(timer, 10000);
<pre id="results"></pre>
When I run your code in the Firebug debugger, I see:
TypeError: can't convert console.log(...) to string
I added a comment to your code about that error:
function timer() {
var time=10;
for(i=0; i<time; i++){
// The source of error is the line below
// Type error: setTimeout needs a function as first argument!
setTimeout(console.log(i+1), 1000);
}
}
setInterval(timer, 10000);
A corrected version might be
function timer() {
var time=10;
for(i=0; i<time; i++){
setTimeout(function() { console.log(i+1); }, 1000);
}
}
setInterval(timer, 10000);
However, the above change fixes the type error but not the logic.
You probably wanted to do this:
var counter = 0;
var count = function() {
console.log(++counter);
if (counter >= 10) {
clearInterval(timer);
}
};
var timer = setInterval(count, 1000);
Once the callback function count notices the counter passed the value 10 it will stop the periodic timer whose ID was saved in the variable timer when setting it up.

Combine for loop with timing events in javascript

I have this code:
for (i = 0; i < 3; i++) {
var interval = setInterval(function(){
alert(i);
}, 2000);
}
What I would like to achieve is to have an alert every 2 sec displaying first 0, then 1 and lastly 2.
Instead I have to wait for quite long before I have 3 alerts all displaying the number 3. Where is my code wrong?
Well, there is (yet again) more than one solution to this problem. But, lets first talk why your code doesn't work properly.
Your code:
for (i = 0; i < 3; i++) {
var interval = setInterval(function(){
alert(i);
}, 2000);
}
..basically means that it will assign three setInterval calls to be executed after 2 seconds as fast as the for loop is placing them to the queue. So basically, all your calls runs really fast after 2 seconds, only few milliseconds or less between them. Moreover, setInterval means that it will be called as long as clearInterval is called to the variable it is assigned with. In other words, your code never stops executing the alert, because you are never calling clearInterval. Finally, your alert(i) will always display value of 3, because it is the last value of i when execution moves away from the for loop.
To improve your code, you could remove the for loop entirely and just let setInterval run as long as the value of i is alerted three times; At that point, you just call clearInterval to the value which has handle to setInterval and the job is finished.
Working code:
// value to output
var i = 0,
// starting setInterval and assigning its handle to variable interval,
// it is used to clear the interval when execution should be finished
interval = setInterval(function () {
// alert value of i and increase it by 1
alert(i++);
// if i is equals to 3, no more calls
if(i === 3) {
// clear the interval so method won't be called in the future
clearInterval(interval);
}
}, 2000);
JS FIDDLE EXAMPLE
Cheers, hopefully you learnt something new today.
Without forloop:
var number = 0;
var interval = setInterval(function(){
alert(number);
number++;
if(number === 3) {
clearInterval(interval);
}
}, 2000);
JSFIDDLE
1.1 Without for loop + without initial delay (demo):
var i = 0;
var showAlert = function(){
alert(i);
i++;
if(i < 3){
setTimeout(function(){
showAlert();
}, 2000);
}
};
showAlert();
1.2 Without for loop + with initial delay (demo):
var i = 0;
var showAlert = function(){
if(i < 3){
setTimeout(function(){
alert(i);
i++;
showAlert();
}, 2000);
}
};
showAlert();
2.1 With for loop + without initial delay (demo):
function setAlert(k){
setTimeout(function(){
alert(k);
},k * 2000);
}
for(var i = 0; i < 3; i++) {
setAlert(i);
}
2.2 With for loop + with initial delay (demo):
function setAlert(k){
setTimeout(function(){
alert(k);
},(k + 1) * 2000);
}
for(var i = 0; i < 3; i++) {
setAlert(i);
}
First of all, I would go with setTimout, you know that you want 3 alerts.
Second problem is a bit stranger. You are calling async function, setTimeout/setInterval and referring to the original i of the for loop inside of the setTimeout callback. That will not work because at the time of the timeout invocation the for loop has already finished and i var will be 3. One solution is to wrapp the async function in a self invoking anonymous function with params that you need inside async function. In our case we call it with i.
Solution:
for (i = 0; i < 3; i++) {
(function(i) {
setTimeout(function(){
alert(i);
}, 2000 * i);
})(i);
}
JS fiddle

Javascript setTimeout in foreach: need help creating a closure

I have this function
notes.forEach(function(note) {
setTimeout(function() {
playNote(note);
}, 1000);
});
This doesn't work. It plays all the notes at the same time, instead of playing them sequentially with a 1 second gap in between. It looks like I need to have a closure here to make this work. Could someone help me fix this function so it would play the note with the delay between each note?
There are two ways to do this:
1) Have a function that grabs one note every second until there are no more notes:
var interval = setInterval(function() {
playNote(notes.shift()); // changes the notes array!
if (!notes.length) clearInterval(interval);
}, 1000);
2) Start all the timers at the same time with different delays:
notes.forEach(function(note, index) {
setTimeout(playNote.bind(null, note), index*1000);
});
because all timeouts are set at the same time...
Do something like this:
playAllNotes(0);
function playAllNotes(index) {
if(notes.length > index) {
setTimeout(function() {
playNote(notes[index]);
playAllNotes(++index);
}, 1000);
}
}
You can use a counter, it's tricky but worth it if you are working with objects:
counter = 0;
$.each(object, function(index,item){
counter++;
var localCounter = counter;
setTimeout(function{
console.log('something')
}, counter * 1000) // change one to number of milliseconds you need
})
First counter is global, so if we don't user var localCounter we would execute all timeouts at the same time.

Delay JavaScript's function execution

I have a JQuery's .each loop that calls a function with a parameter per iteration, is there a way to delay this function call? I have tried setTimeout as in the following but this does not work as the function gets executed immediately.
$.each(myArray, function (j, dataitem)
{
setTimeout(function () { showDetails(dataitem) }, 300);
});
function showDetails(dataitem)
{
...
}
Array size is roughly 20, What I'm trying to do is to distribute function calls over a certain time frame instead of immediately, any idea how to achieve this? I'm prepared to rewrite and restructure how functions get called to get this done, any help would be appreciated.
You could use the index of the array to calculate the interval dynamically:
$.each(myArray, function (j, dataitem) {
window.setTimeout(function () {
showDetails(dataitem)
}, (j + 1) * 300);
});
You execute them all after 300 milliseconds. Instead, try something like this:
window.setTimeout(function () { showDetails(dataitem) }, (j + 1) * 300);
Edit: instead of creating 20 timers at once I think it's better to do it one by one. Function should be:
function showDetails(index)
{
if (index >= myArray.length)
return false;
var dataItem = myArray[index];
//code here......
//code here......
//code here......
windows.setTimeout(function() { showDetails(index + 1); }, 300);
}
And first call can be:
$(document).ready(function() {
{
showDetails(0);
});
This assume myArray is plain global array, and will handle one item and only then call the next item with delay.
Take a look at jQuery.queue([ queueName ], callback( next )). This allows you to queue functions up to be called and is what jQuery's animation effects use internally.
It sounds like you would like to implement a queue, although it is not entirely clear you intentions for doing so.
EDIT: re-reading your question, I think other answers better match what you are after, however I thought that I would show you an example of how to achieve delayed function execution with a custom queue.
An example of how you could use a queue.
var myArray = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],
output = $('#output');
// set the queue up
$.each(myArray, function (j, dataitem) {
output.queue('queue', function(next) {
var that = this;
showDetails(dataitem);
window.setTimeout(next,300);
});
});
// start the queue running.
output.dequeue('queue');
function showDetails(dataitem) {
output.append('<div>' + dataitem + '</div>');
}
Just don't use $.each, but something like:
var data = [1, 2, 3, 4, 5];
function showDetails(values, delay) {
console.log(values.shift()); //show the value
if (values.length) {
setTimeout(function() {showDetails(values, delay); }, delay); //schedule next elem
}
}
showDetails(data.slice(0), 300); //dont forget the slice, call-by-reference

Create a pause inside a while loop in Javascript

I would like to create a pause inside a while loop so that I can create n animations that each appear 3 seconds after the other.
I've tried the following, but it doesn't work. Would love to have someone show me what I'm doing wrong.
i=0;
while (i < n) {
someanimation();
setTimeout(function(){
i++;
}, 3000);
};
setTimeout does not pause; it asks Javascript to run some other code later.
Googling for "setTimeout loop" tells you exactly what you need to know. If you look around a little bit, it even mentions setInterval. The difference: using setTimeout to loop will wait 3 seconds in between loops, whereas setInterval will make it take 3 seconds total for the loop (including however much time the animation takes, as long as it's less than 3 seconds :) ). Also, setInterval constructs an infinite loop that you'll have to break out of after the desired number of times; setTimeout requires you to construct the loop yourself.
i = 0;
// setTimeout approach
function animation_loop() {
someAnimation();
setTimeout(function() {
i++;
if (i < n) {
animation_loop();
}
}, 3000);
};
animation_loop();
// setInterval approach
i = 0;
someAnimation();
iid = setInterval(function() {
i++;
if (i < n) {
someAnimation();
} else {
clearInterval(iid);
}
}, 3000);
setTimeout is a little trickier than that because it doesn't block (i.e. it doesn't finish waiting on the timeout before continuing with the program).
What you want is closer to this:
var i = 0;
function nextFrame() {
if(i < n) {
someanimation();
i++;
// Continue the loop in 3s
setTimeout(nextFrame, 3000);
}
}
// Start the loop
setTimeout(nextFrame, 0);
It may also be worth your while to read up on setInterval as a possible alternative.
Well, thanks to ES6-7 with Promises we can now make a pause and make it look nice at the same time!
var id = 0;
async function do() {
while(true) {
await pause(id);
//will happen only after pause is done
id++;
}
}
function pause(id) {
return new Promise(resolve => setTimeout(() => {
console.log(`pause ${id} is over`);
resolve();
}, 1500));
}
do();
One of the way of doing it is to use RxJS. Please take a look at working example here
Rx.Observable
.interval(1000)
.take(10)
.subscribe((x) => console.log(x))
create a function like:
function sleep_until (seconds) {
var max_sec = new Date().getTime();
while (new Date() < max_sec + seconds * 1000) {}
return true;
}
and then change your code to
i=0;
while (i < n) {
someanimation();
sleep_until(3);
do_someotheranimation();
};
You are not very specific about what you want to do, but I'd say the main problem is that you call someanimation() without a delay. So maybe this solves it for you:
for (var i = 0; i < n; i++) {
setTimeout(someanimation, 3000 * i);
};
Note the missing () after someanimation as it is the callback for setTimeout().
function myFunction() {
var x;
for(var i=0;i<10;i++){
if (confirm("Press a button!") == true) {
x = "You pressed OK!";
} else {
x = "You pressed Cancel!";
}
document.getElementById("demo").innerHTML = x;
}
}``

Categories

Resources