How to set loop with pause in between each log - javascript

How could I make a loop that pauses for a set amount of time before repeating?
I tried using setTimeout inside of a while loop but that didn't work.

JavaScript is monothreaded, so blocking is to be avoided, that is why so much effort was pourred into the language to standardise Promise and add async / await
This allow to pause code execution without blocking, here how you do it:
// Only available in Node v15+
import { setTimeout as pause } from 'timers/promises'
// if not in node:
const pause = delay => new Promise(s => setTimeout(s, delay))
async function sayHelloEverySeconds() {
while (true) {
await pause(1000) // 1 sec
console.log('hello')
}
}
sayHelloEverySeconds()
But for this exact function, it would be simpler to use setInterval directly:
setInterval(() => console.log('hello'), 1000)
this will execute the function every seconds

You don't need to use async/await functions or promises or a while loop. Call a function and have setTimeout call the function again after a set amount of time.
function loop(count = 0) {
console.log(count);
setTimeout(loop, 1000, ++count);
}
loop();

Related

Any easier way to create CSS value change animations with javascript [duplicate]

I need to execute 3 functions in a 1 sec delay.
for simplicity those functions are :
console.log('1');
console.log('2');
console.log('3');
I could do this: ( very ugly)
console.log('1')
setTimeout(function () {
setTimeout(function () {
console.log('2')
setTimeout(function () {
console.log('3')
}, 1000)
}, 1000)
}, 1000)
Or I could create an array of functions and use setInterval with global counter.
Is there any elegant way of doing this ?
(p.s. function no.2 is not dependent on function number 1... hence - every sec execute the next function.).
You can use something like this with setTimeout:
var funcs = [func1, func2, func3],
i = 0;
function callFuncs() {
funcs[i++]();
if (i < funcs.length) setTimeout(callFuncs, 1000);
}
setTimeout(callFuncs, 1000); //delay start 1 sec.
or start by just calling callFuncs() directly.
Update
An setInterval approach (be aware of the risk of call stacking):
var funcs = [func1, func2, func3],
i = 0,
timer = setInterval(callFuncs, 1000);
function callFuncs() {
funcs[i++]();
if (i === funcs.length) clearInterval(timer);
}
Assuming you run it on a modern browser or have added support for array.map this is quite concise:
[func1, func2, func3].map(function (fun, index) {
setTimeout(fun, 1000 + index * 1000);
}
setTimeout(function(){console.log('1')}, 1000);
setTimeout(function(){console.log('2')}, 2000);
setTimeout(function(){console.log('3')}, 3000);
There is a new type of function declaration called generators in es6 (a.k.a ecmascript 6, es2015). It is incredibly useful for this situation, and makes your async code look synchronous. es6 is the latest standard of JavaScript as of 2015. It works on modern browsers but you can use Babel and its javascript polyfill to use generators now even on older browsers.
Here is a tutorial on generators.
The function myDelayedMessages below is an example of a generator. Run is a helper function that takes a generator function which it calls and provides a function to advance the generator as the first argument of the generator function that it called.
function delay(time, callback) {
setTimeout(function () {
callback();
}, time);
}
function run(generatorFunction) {
var generatorItr = generatorFunction(resume);
function resume(callbackValue) {
generatorItr.next(callbackValue);
}
generatorItr.next()
}
run(function* myDelayedMessages(resume) {
for(var i = 1; i <= 3; ++i) {
yield delay(1000, resume);
console.log(i);
}
});
This is an overview of the code which is similar to the above tutorial's final overview.
run takes our generator and creates a resume function. run creates a
generator-iterator object (the thing you call next on), providing
resume.
Then it advances the generator-iterator one step to kick
everything off.
Our generator encounters the first yield statement
and calls delay.
Then the generator pauses.
delay completes 1000ms later and calls resume.
resume tells our generator to advance a single step.
Our generator continues from the spot it yielded at then console.logs i, which is 1, then continues the loop
Our generator encounters the second call to yield,
calls delay and pauses again.
delay waits 1000ms and ultimately
calls the resume callback. resume advances the generator again.
Our generator continues from the spot it yielded at then console.logs i, which is 2, then continues the loop.
delay waits 1000ms and ultimately
calls the resume callback. resume advances the generator again.
Our generator continues from the spot it yielded at then console.logs i, which is 3, then continues and the loop finishes.
There are no more calls to yield, the generator finishes executing.
with async/await
const pause = _ => new Promise(resolve => setTimeout(resolve, _));
async function main() {
await pause(1000);
console.log('one');
await pause(1000);
console.log('two');
await pause(1000);
console.log('three');
}
main();
note this works in a loop too
const pause = _ => new Promise(resolve => setTimeout(resolve, _));
async function main() {
for (let i = 0; i < 3; ++i) {
await pause(1000);
console.log(i + 1);
}
}
main();
I think most simple way to do this is to create some closures within a function.
First i'll recall that you have big interest in using setInterval, since the overhead of the setTimeout might have it trigger 10ms off target. So especially if using short (<50ms) interval, prefer setInterval.
So we need to store the function array, the index of latest executed function, and an interval reference to stop the calls.
function chainLaunch(funcArray, time_ms) {
if (!funcArray || !funcArray.length) return;
var fi = 0; // function index
var callFunction = function () {
funcArray[fi++]();
if (fi==funcArray.length)
clearInterval(chainInterval);
} ;
var chainInterval = setInterval( callFunction, time_ms);
}
Rq : You might want to copy the function array ( funcArray = funcArray.slice(0); )
Rq2 : You might want to loop within the array
Rq3 : you might want to accept additionnal arguments to chainlaunch. retrieve them with var funcArgs = arguments.slice(3); and use apply on the functions : funcArray[fi++].apply(this,funcArgs);
Anyway the following test works :
var f1 = function() { console.log('1'); };
var f2 = function() { console.log('2'); };
var f3 = function() { console.log('3'); };
var fArr = [f1, f2, f3];
chainLaunch(fArr, 1000);
as you can see in this fiddle : http://jsfiddle.net/F9UJv/1/
(open the console)
There are here two methods. One with setTimeout and anotherone with setInterval. The first one is better in my opinion.
for(var i = 1; i++; i<=3) {
setTimeout(function() {
console.log(i);
}, 1000*i);
}
// second choice:
var i = 0;
var nt = setInterval(function() {
if(i == 0) return i++;
console.log(i++);
if(i>=3) clearInterval(nt);
}, 1000);

How to run a delay function for 5 times in JavaScript?

I want to run a delay function for five seconds in JavaScript which will print "Hello" in the console after every second for five times.
Similar Python Code:
from time import delay
for I in range(5):
print("Hello")
delay(1)
The above code will print "Hello" five times with one second delay between each print.
Now I want to do similar kind of operation in JS.
Now in JS we have setTimeout function which will call a function after after a specified time. The following code will print "Hello" in the console after 1 second interval.
setTimeout(function(){
console.log("Hello");
}, 1000);
How can I run this code that will print 'Hello' in the console five times with an one second delay between each print?
NB: I tried to pass this function inside a for loop, but it did not work.
Try like this:
var count = 5;
printWithDelay();
function printWithDelay() {
setTimeout(function() {
console.log("Hello");
count--;
if (0 < count) {
printWithDelay();
};
}, 1000);
};
In JavaScript, 'setTimeout' runs after the code that follows it, so the next iteration of the loop needs to be called from within the callback function for this to work.
JavaScript, unlike PHP and Python, is asynchronous. The event loop is sensitive to anything that blocks it. However, there are ways to achieve what you want.
setInterval
With setInterval, you can build a wrapper it and use it.
function repeatFunction(func, delay, repeat) {
let counter = 0;
let interval = setInterval(() => {
if (repeat !== counter) {
func();
counter++;
} else {
clearInterval(interval)
}
}, delay);
}
repeatFunction(() => console.log(5), 1000, 4)
async/await syntax
The other option is using async/await with Promises (recommended)
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
(async() => {
for (let i = 0; i < 5; i++) {
console.log(i);
await sleep(1000);
}
console.log('done')
})();
Use setInterval, this should get your job done!
const test = setInterval(() => console.log("Hello"), 1000);
And then after 5seconds remove interval
setTimeout( () => clearInterval(test), 5000)
const test = setInterval(() => document.body.innerText += "Hello", 1000);
setTimeout( () => clearInterval(test), 5000);
NOTE: The first console.log() will happen after a second, if you want it immediately just put one console.log() outside the setInterval.

Why doesn't my setTimeout callback not get called?

I'm busy building a flash-card game. I want to give the user a visible countdown before a card get's flashed on screen. My script for the countdown looks like this:
let downSeconds = 5;
while (downSeconds > 0) {
setTimeout(function() {
$("#timerDisplay").text = downSeconds;
downSeconds--;
}, 1000);
}
$(".detail-card").removeClass("hidden");
If I didn't want the updated seconds I'd just use a 5000ms 'setTimeOut'. I did before try with a setInterval, with a delay of 1000ms, so every time it elapses it updates the seconds.
Now, if I put a breakpoint on either line of the setTimeOut callback, and only there, nothing happens when the setTimeout is invoked, so the seconds display never updates, and I'm in an infinite loop, because downSeconds--; is never invoked, so downSeconds keeps the value of 5 all throughout.
What am I doing wrong?
setTimeout runs the code later, while the while loop runs "now". You can't successfully combine the two.. So, you have to write your code differently, something like this should work:
let downSeconds = 5;
function doCountDown() {
downSeconds--;
$("#timerDisplay").text = downSeconds;
if (downSeconds > 0) {
setTimeout(doCountDown, 1000);
} else {
$(".detail-card").removeClass("hidden");
}
}
setTimeout(doCountDown, 1000);
You may use ES7 and await the loop for a second:
const time = ms => new Promise(res => setTimeout(res,ms));
(async function(){
let downSeconds = 5;
while (downSeconds > 0) {
await time(1000);
$("#timerDisplay").text = downSeconds;
downSeconds--;
}
$(".detail-card").removeClass("hidden");
})()
The setTimeout call is asynchronous,
and so by the time the 1000 milliseconds scheduled by the first call to setTimeout elapses,
the while-loop will have executed its body thousands of times,
each time scheduling a new job with setTimeout,
causing massive scheduling work to the JavaScript engine.
The engine is too busy to execute the function,
and it just keeps getting worse,
as the loop keeps running and keeps scheduling more and more.
I would expect your execution environment to become unresponsive and unable to make progress, unable to actually call the first function scheduled.
Use setInterval and clearInterval instead, for example:
let counter = 5;
let interval = setInterval(() => {
$("#timerDisplay").text = counter;
counter--;
if (counter == 0) {
clearInterval(interval);
$(".detail-card").removeClass("hidden");
}
}, 1000);

Wait 5 seconds before executing next line

This function below doesn’t work like I want it to; being a JS novice I can’t figure out why.
I need it to wait 5 seconds before checking whether the newState is -1.
Currently, it doesn’t wait, it just checks straight away.
function stateChange(newState) {
setTimeout('', 5000);
if(newState == -1) {
alert('VIDEO HAS STOPPED');
}
}
Browser
Here's a solution using the new async/await syntax.
Be sure to check browser support as this is a language feature introduced with ECMAScript 6.
Utility function:
const delay = ms => new Promise(res => setTimeout(res, ms));
Usage:
const yourFunction = async () => {
await delay(5000);
console.log("Waited 5s");
await delay(5000);
console.log("Waited an additional 5s");
};
The advantage of this approach is that it makes your code look and behave like synchronous code.
Node.js
Node.js 16 provides a built-in version of setTimeout that is promise-based so we don't have to create our own utility function:
import { setTimeout } from "timers/promises";
const yourFunction = async () => {
await setTimeout(5000);
console.log("Waited 5s");
await setTimeout(5000);
console.log("Waited an additional 5s");
};
⚠️ Just for the record, you might be tempted to use a wait function to circumvent race conditions (when testing asynchronous code for example). This is rarely a good idea.
You have to put your code in the callback function you supply to setTimeout:
function stateChange(newState) {
setTimeout(function () {
if (newState == -1) {
alert('VIDEO HAS STOPPED');
}
}, 5000);
}
Any other code will execute immediately.
You really shouldn't be doing this, the correct use of timeout is the right tool for the OP's problem and any other occasion where you just want to run something after a period of time. Joseph Silber has demonstrated that well in his answer. However, if in some non-production case you really want to hang the main thread for a period of time, this will do it.
function wait(ms){
var start = new Date().getTime();
var end = start;
while(end < start + ms) {
end = new Date().getTime();
}
}
With execution in the form:
console.log('before');
wait(7000); //7 seconds in milliseconds
console.log('after');
I've arrived here because I was building a simple test case for sequencing a mix of asynchronous operations around long-running blocking operations (i.e. expensive DOM manipulation) and this is my simulated blocking operation. It suits that job fine, so I thought I post it for anyone else who arrives here with a similar use case. Even so, it's creating a Date() object in a while loop, which might very overwhelm the GC if it runs long enough. But I can't emphasize enough, this is only suitable for testing, for building any actual functionality you should refer to Joseph Silber's answer.
If you're in an async function you can simply do it in one line:
console.log(1);
await new Promise(resolve => setTimeout(resolve, 3000)); // 3 sec
console.log(2);
FYI, if target is NodeJS you can use this built-in function if you want (it's a predefined promisified setTimeout function):
import { setTimeout } from 'timers/promises';
await setTimeout(3000); // 3 sec
Use a delay function like this:
var delay = ( function() {
var timer = 0;
return function(callback, ms) {
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
})();
Usage:
delay(function(){
// do stuff
}, 5000 ); // end delay
Credits: How to delay the .keyup() handler until the user stops typing?
You should not just try to pause 5 seconds in javascript. It doesn't work that way. You can schedule a function of code to run 5 seconds from now, but you have to put the code that you want to run later into a function and the rest of your code after that function will continue to run immediately.
For example:
function stateChange(newState) {
setTimeout(function(){
if(newState == -1){alert('VIDEO HAS STOPPED');}
}, 5000);
}
But, if you have code like this:
stateChange(-1);
console.log("Hello");
The console.log() statement will run immediately. It will not wait until after the timeout fires in the stateChange() function. You cannot just pause javascript execution for a predetermined amount of time.
Instead, any code that you want to run delays must be inside the setTimeout() callback function (or called from that function).
If you did try to "pause" by looping, then you'd essentially "hang" the Javascript interpreter for a period of time. Because Javascript runs your code in only a single thread, when you're looping nothing else can run (no other event handlers can get called). So, looping waiting for some variable to change will never work because no other code can run to change that variable.
setTimeout(function() {
$('.message').hide();
}, 5000);
This will hide the '.message' div after 5 seconds.
This solution comes from React Native's documentation for a refresh control:
function wait(timeout) {
return new Promise(resolve => {
setTimeout(resolve, timeout);
});
}
To apply this to the OP's question, you could use this function in coordination with await:
await wait(5000);
if (newState == -1) {
alert('Done');
}
Try this:
//the code will execute in 1 3 5 7 9 seconds later
function exec() {
for(var i=0;i<5;i++) {
setTimeout(function() {
console.log(new Date()); //It's you code
},(i+i+1)*1000);
}
}
Best way to create a function like this for wait in milli seconds, this function will wait for milliseconds provided in the argument:
function waitSeconds(iMilliSeconds) {
var counter= 0
, start = new Date().getTime()
, end = 0;
while (counter < iMilliSeconds) {
end = new Date().getTime();
counter = end - start;
}
}
Based on Joseph Silber's answer, I would do it like that, a bit more generic.
You would have your function (let's create one based on the question):
function videoStopped(newState){
if (newState == -1) {
alert('VIDEO HAS STOPPED');
}
}
And you could have a wait function:
function wait(milliseconds, foo, arg){
setTimeout(function () {
foo(arg); // will be executed after the specified time
}, milliseconds);
}
At the end you would have:
wait(5000, videoStopped, newState);
That's a solution, I would rather not use arguments in the wait function (to have only foo(); instead of foo(arg);) but that's for the example.
You can add delay by making small changes to your function ( async and await ).
const addNSecondsDelay = (n) => {
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, n * 1000);
});
}
const asyncFunctionCall = async () {
console.log("stpe-1");
await addNSecondsDelay(5);
console.log("step-2 after 5 seconds delay");
}
asyncFunctionCall();
If you have an asyn function you can do:
await new Promise(resolve => setTimeout(resolve, 5000));

using setTimeout synchronously in JavaScript

I have the following scenario:
setTimeout("alert('this alert is timedout and should be the first');", 5000);
alert("this should be the second one");
I need the code after the setTimeout to be executed after the code in the setTimeout is executed. Since the code that comes after the setTimeout is not code of my own I can't put it in the function called in the setTimeout...
Is there any way around this?
Is the code contained in a function?
function test() {
setTimeout(...);
// code that you cannot modify?
}
In that case, you could prevent the function from further execution, and then run it again:
function test(flag) {
if(!flag) {
setTimeout(function() {
alert();
test(true);
}, 5000);
return;
}
// code that you cannot modify
}
I came in a situation where I needed a similar functionality last week and it made me think of this post. Basically I think the "Busy Waiting" to which #AndreKR refers, would be a suitable solution in a lot of situations. Below is the code I used to hog up the browser and force a wait condition.
function pause(milliseconds) {
var dt = new Date();
while ((new Date()) - dt <= milliseconds) { /* Do nothing */ }
}
document.write("first statement");
alert("first statement");
pause(3000);
document.write("<br />3 seconds");
alert("paused for 3 seconds");
Keep in mind that this code acutally holds up your browser.
Hope it helps anyone.
Using ES6 & promises & async you can achieve running things synchronously.
So what is the code doing?
1. Calls setTimeOut 1st inside of demo then put it into the webApi Stack
2. Creates a promise from the sleep function using the setTimeout, then resolves after the timeout has been completed;
3. By then, the first setTimeout will reach its timer and execute from webApi stack.
4. Then following, the remaining alert will show up.
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function demo() {
setTimeout("alert('this alert is timedout and should be the first');", 5000);
await sleep(5000);
alert('this should be the second one');
}
demo();
Just put it inside the callback:
setTimeout(function() {
alert('this alert is timedout and should be the first');
alert('this should be the second one');
}, 5000);
No, as there is no delay function in Javascript, there is no way to do this other than busy waiting (which would lock up the browser).
ES6 (busy waiting)
const delay = (ms) => {
const startPoint = new Date().getTime()
while (new Date().getTime() - startPoint <= ms) {/* wait */}
}
usage:
delay(1000)
You can create a promise and await for its fulfillment
const timeOut = (secs) => new Promise((res) => setTimeout(res, secs * 1000));
await timeOut(1000)
Here's a good way to make synchronous delay in your code:
async function yourFunction() {
//your code
await delay(n);
//your code
}
function delay(n) {
n = n || 2000;
return new Promise(done => {
setTimeout(() => {
done();
}, n);
});
}
Found it here Right way of delaying execution synchronously in JavaScript without using Loops or Timeouts!
setTimeout(function() {
yourCode(); // alert('this alert is timedout and should be the first');
otherCode(); // alert("this should be the second one");
}, 5000);
I think you have to make a promise and then use a .then() so that you can chain your code together. you should look at this article https://developers.google.com/web/fundamentals/primers/promises
You could attempt to replace window.setTimeout with your own function, like so
window.setTimeout = function(func, timeout) {
func();
}
Which may or may not work properly at all. Besides this, your only option would be to change the original code (which you said you couldn't do)
Bear in mind, changing native functions like this is not exactly a very optimal approach.

Categories