I'm facing a question here that I need to run, for example, 2 function per time, wait just 2 minutes and start run these two function again, just like a loop with a pause between the batches.
I've tried something here, and I know that my issue is, every time I start the myFunction with start function as callback I get a duplicated call. But right now, I really don't know what is the best approach to follow.
var count = 0;
function myFunction() {
console.log('function called', count);
start();
}
function batch () {
for (i = 0; i < 2; i++) {
myFunction();
console.log('batch', i);
}
console.log('--------------');
}
function start() {
console.log('started')
setTimeout(function() {
batch();
}, 2000);
count++;
}
start();
Thank you for suggestions ;)
From what I understand, you want to execute two functions every two minutes.
Have you tried using window.setInterval?
const func1 = () => console.log('func1 called');
const func2 = () => console.log('func2 called');
window.setInterval(() => {
func1();
func2();
}, 1000);
Now, func1 and func2 will be called every second.
Related
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);
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.
What I want to do is stop a function running from ANOTHER function (in JavaScript). here is an example of what I would like to do:
async function process1(){ //this is a normal function running
//here is a long list of instruction that can take some time (~ 30s)
}
function STOPprocess1(){
process1().Stop; //this is pseudoCode !
}
When I call STOPprocess1() , I want the process1 function to stop running.
You could try something like this:
var flag = true;
async function process1(){ //this is a normal function running
while(flag){
await sleep(50); //we suppose we have the function sleep.
console.log("the function process1 is running...");
}
}
function STOPprocess1(){
flag = false;
}
But you may have problems with the scope...
Use a global variable to stop process 1
let isRunning = true;
async function process1(){ //this is a normal function running
while(isRunning){
await sleep(50); //we suppose we have the function sleep.
console.log("the function process1 is running...");
}
}
function STOPprocess1(){
isRunning = false;
}
How about using generator functions for that? If you yield, defer the call to .next() to a microtask, thus making it possible to interrupt:
function interruptable(gen) {
return function(...args) {
let timer, it = gen(...args);
function next() {
const { done } = it.next();
if(!done) timer = setTimeout(next, 0);
}
next();
return () => clearTimeout(timer);
};
}
const task = interruptable(function* () {
while(true) {
console.log("running");
yield;
}
});
const stop = task();
setTimeout(stop, 1000);
I would suggest setInterval over the use of a while loop (while(true) is generally frowned upon). You can then use clearInterval to stop execution.
let intervalId;
async function process1(){ //this is a normal function running
intervalId = setInterval(() => console.log("the function process1 is running..."), 50);
}
function STOPprocess1(){
clearInterval(intervalId)
}
while(true) might break your browser or whatever you're using. You can use setInterval() instead and use clearInterval() to stop the process.
//before starting the function
var process1;
//when starting the function
var process1 = setInterval(function() {
console.log("the function process1 is running...");
}, 50);
//to stop the function
function STOPprocess1(){
clearInterval("process1");
}
var cnt = 1;
var running = true;
process1();
async function process1(){
if(running){
await new Promise(resolve => setTimeout(resolve, 50));
document.getElementById("tstArea").innerHTML="this: "+ cnt;
cnt++;
process1();
}
}
function stopOtherFn(){
running = false;
}
<div id="tstArea">
</div>
<button onClick="stopOtherFn()">StopThat</button>
here is a rough mockup that seems to accomplish what you are looking for.
If you want to iterate something without stopping instead another function asks for it:
I would not do that. I believe every function should control itself. If the function dedicated to stop another function append to fail, the cost in term of ressources and time to fix it may become problematic.
Instead, I'd create a function calling another function after checking something else (cookie, data, variable).
const checkSomething = () => {
// var in parameter, cookie, data from API, etc
// if necessary throw new Error
if (something) return true;
return false;
};
const something = () => {
console.log('I did that');
};
const periodicallyDoSomething = () => {
try {
let continueDoingSomething = checkSomething();
while (continueDoingSomething) {
something();
continueDoingSomething = checkSomething();
}
} catch (e) {
console.error(e.message);
} finally {
console.log('I did it!');
}
};
// run it, or export it as in module.exports
If you want a function to do something that takes a lot if time while still being able to stop it externally, like a classic CTRL+C:
This should be inside your function.
I believe that a function dedicated to do something should be the same function finishing it.
Try/catch/finally, like I used it juste before, may be interesting.
Have a happy coding time. :)
I have a button with click function below. It has 3 nested for loop, and 1 setTimeout function.
The below loops are looping 5 times. I want below code to work(5x5) total 25 seconds of execution time, and each 5 seconds console output should be "Waited" printed.
However below code works only 5 seconds, and immediately prints "5 hello". Without changing my for loop structure, how can I make it work as I want?
jQuery("#btn_trendyolStocksSYNC").click(function() {
for(var product in all){
var colors = all[product];
for(var singleColor in colors[0]){
var size = colors[0][singleColor];
for(var index in size){
var singleSize = size[index];
setTimeout(function (){
console.log('Waited');
}, 5000);
}
}
}
});
Edit: I don't use the for loop with indexes, so solutions for number indexed for loops are not working for me.
You could try by adding await and a Promise:
jQuery("#btn_trendyolStocksSYNC").click(async function() {
for(var product in all){
var colors = all[product];
for(var singleColor in colors[0]){
var size = colors[0][singleColor];
for(var index in size){
var singleSize = size[index];
await new Promise(resolve => setTimeout(function (){
console.log('Waited');
resolve();
}, 5000));
}
}
}
});
What this does is simply tell your loop to stop and only continue once the Promise object calls its resolve parameter function. That way your delay should simply happen before the next iteration. This is the important code:
await new Promise(resolve => setTimeout(function (){
console.log('Waited');
resolve();
}, 5000));
It simply creates a Promise that we will resolve once the timeout has let 5000 milliseconds pass. Then we tell our loop to simply await that completion before continuing to the next item.
Note You also need to add async to your handler function, so javascript knows that this function can wait and take as long as it needs to.
The setTimeout(); function is asynchronous, meaning that your script will not wait for it to finish before moving on. That's why it has a callback.
Try something like this: (not the best method)
//delayed loop
var i = 1;
function loop() {
//wait 5 secs
setTimeout(function() {
console.log(i);
if(i>5) {
//cancel
return;
}
loop();
i++;
return;
}, 1000);
if(i>5) {
//cancel function
return;
}
}
//do the loop
loop();
Like what somethinghere said, you could put the setTimeout in the if statement.
Of course to do something after the loop ends you need a callback function.
you can use setInterval and clearInterval.
var n=0;
var a = setInterval(()=>{
console.log("Waited");
n++; if(n==5){clearInterval(a);}
},5000);
I have a function that is used to send messages and that is called multiple times in a sec.
But I want to call that function once a sec and delay other calls of that function with another 1-second of the previous call.
So that only that function run in the background and called once in a second, no matters how many times it is called it will delay each call to one second ahead.
For example:
function foo(a) {
console.log(a)
}
foo('one');
foo('two');
foo('three');
in the above example, foo is called three times within a sec but I want to have it called like after the 1 second it should return "one" after 2 seconds it should return 'second' and so on and it should be asynchronous.
How can I do this?
The technology I am using is Javascript.
Thanks
Well this is the first thing I came up with - perhaps it's crude.
var queuedUpCalls = [];
var currentlyProcessingCall = false;
function foo(a) {
if (currentlyProcessingCall) {
queuedUpCalls.push(a);
return;
}
currentlyProcessingCall = true;
setTimeout(function(){
console.log(a);
currentlyProcessingCall = false;
if (queuedUpCalls.length) {
var nextCallArg = queuedUpCalls.shift();
foo(nextCallArg);
}
},1000);
}
foo('one');
foo('two');
foo('three');
For each call, if you're not currently processing a call, just call setTimeout with a delay of 1000ms. If you are processing a call, save off the argument, and when the setTimeout that you kicked off finishes, process it.
Somewhat improved answer using setInterval:
var queuedUpCalls = [];
var timerId;
function foo(a) {
queuedUpCalls.push(a);
if (timerId) {
return;
}
timerId = setInterval(function(){
if (!queuedUpCalls.length) {
clearInterval(timerId);
timerId = null;
return;
}
var nextCallArg = queuedUpCalls.shift();
console.log(nextCallArg);
}, 1000);
}
foo('one');
foo('two');
foo('three');
Here is a simple queue system, it basically just pushes the functions onto an array, and then splice's them off every second.
const queue = [];
setInterval(function () {
if (!queue.length) return;
const f = queue[0];
queue.splice(0, 1);
f();
}, 1000);
function foo(a) {
queue.push(function () {
console.log(a)
});
}
foo('one');
foo('two');
foo('three');
you could use this to run the main code first and then run some more code a little later.
function firstfunction() {
alert('I am ran first');
setTimeout(function(){ alert('I am ran 3 seconds later') }, 3000);
}
<button onclick="firstfunction();">click me</button>
function foo(a)
{
if (typeof foo.last == 'undefined')
foo.last = Date.now();
var now = Date.now();
if (now - 1000 > foo.time)
foo.last = now;
setTimeout(function()
{
console.log(a);
}, (foo.last += 1000) - now);
}
This will queue each console.log call with intervals of 1 second, the first call will also be delayed by 1 second.
You could do this:
function foo() {
console.log(“ran”);
}
setInterval(foo, 1000);
In the last line, writing foo() without parenthesis is intentional. The line doesn’t work if you add parentheses.