Loop iteration with time interval before passing value to included function - javascript

I'm trying to figure out how to set time out for function inside the loop iteration in Ionic TypeScript application.
setInterval makes equal time interval with calling the function in endless repetition:
setInterval(() => {
this.myFunc1(val);
}, 800);
setTimeout gives required result if listed sequentially:
setTimeout(() => {
this.myFunc1(val);
}, 800);
setTimeout(() => {
this.myFunc1(val);
}, 1200);
but how to loop with time interval trough the updated list and wait while pass second value val to the function, or call myFunc1 when it will be finished in previous iteration:
async myFunc2() {
for (let val of this.myValueList) {
/// wait for 5 sec or wait for finishing process, then pass value calling function:
this.myFunc1(val);
}
}

setInterval is the correct choice here. What's missing is that you need to clear the interval. setInterval returns an id that you can pass to clearInterval which stops the iteration.
Here I'm passing data to console.log, waiting a second, then repeating till done.
const myValueList = [5,6,7,8,9,10];
let i = 0;
const id = setInterval(() => {
console.log(myValueList[i++]);
if (i === myValueList.length) {
clearInterval(id);
console.log("done!");
}
}, 1000);

Simplest solution for waiting approximately 5 seconds:
const wait = t => new Promise(r => setTimeout(r, t));
and then in your code you can just do:
async myFunc2() {
for (let val of this.myValueList) {
await wait(5000);
this.myFunc1(val);
}
}
If myFunc1 is async, and you just want to wait for it to finish executing before continuing the loop, then you would just do:
async myFunc2() {
for (let val of this.myValueList) {
await this.myFunc1(val);
}
}

Related

How can setTimeout run in order

I have two for loop, inside them I have setTimeout function like following code:
for(let i=0;i<3;i++){
setTimeout(()=>{console.log(i)}, 1000)
}
for(let i=0;i<3;i++){
setTimeout(()=>{console.log(i)}, 1000)
}
i want the second loop does not executed until after the first loop finished,
I want this result:
0
1
2
0
1
2
- and between 2 numbers wait 1 second.
how i can do that?
I can't comment yet or I would ask clarifying questions so I'll give you what I think you're asking for. If you want a 1 second delay between each number being logged to the console then this will work:
const func = async () => {
for (let i = 0; i < 3; i++) {
await new Promise((resolve) =>
setTimeout(() => {
console.log(i);
resolve();
}, 1000)
);
}
for (let i = 0; i < 3; i++) {
await new Promise((resolve) =>
setTimeout(() => {
console.log(i);
resolve();
}, 1000)
);
}
};
func();
A quick rundown of what's happening here. I created an outer function named func which I made asynchronous so that I can use the await keyword within it. I then put the setTimeout call inside a new instance of Promise. The promise combined with the await means that javascript will essentially stop at that line until the Promise calls resolve. Once resolve is called that instance of Promise is finished and the await statement stops "blocking" javascript and the callbackque continues.
TLDR:
To use await you must be in an asynchronous function.
If await is used in front of a Promise everything will stop until the promise resolves.
Placing the resolve of the promise inside the callback given to setTimeout ensures that we will wait until each timeout finishes BEFORE the next timeout begins.
This will work
nxt (0, 0);//seed the stack
function nxt(num, itertn){
if(num == 3){//want till 2
if(itertn == 0){// first or 2nd iteration
num =0;
itertn++;
}else{
return;//after 2nd stop
}
}
console.log(num);//the work
num++;
setTimeout(nxt, 1000, num, itertn);//next after a second
}
But there are other ways to do this
I think that you're trying to do sort of a counter
Try something like this:
for(let i=1;i<=3;i++){
setTimeout(()=>{ console.log(i)}, i*1000 )
}
Let me know if this solve your problem
Try nested loop
for(let i=0;i<2;i++){
for(let j=0;j<3;j++){
setTimeout(()=>{console.log(j)}, 1000)
}
}
One solution is create promises, and with map and promise.all, you can group each loop of promises and execute them sequentially.
(async () => {
const second = (i) => new Promise(resolve => setTimeout(() => {
console.log(i)
resolve(i)
}, 1000))
const loop = () => Array(3).fill(0).map(async(item, index) => {
return await second(index)
})
var startTime = performance.now()
await Promise.all(loop())
var endTime = performance.now()
console.log(endTime - startTime)
await Promise.all(loop())
endTime = performance.now()
console.log(endTime - startTime)
})()

SetInterval causes too many re-renders React

Hello I would like to put setInterval in my React project to add 1 for each second but I got an error like in title of this post.
js:
const [activeTab, setActiveTab] = useState(0)
useEffect(() => {
setInterval(setActiveTab(prevTab => {
if (prevTab === 3) return 0
console.log('hi')
return prevTab += 1
}), 1000)
})
There are a few issues:
You're not passing a function to setInterval, you're calling setActiveTab and passing its return value into setInterval.
If you were passing in a function, you'd be adding a new repeated timer every time your componennt ran. See the documentation — useEffect:
By default, effects run after every completed render...
And setInterval:
The setInterval() method... repeatedly calls a function or executes a code snippet, with a fixed time delay between each call.
(my emphasis)
Starting a new repeating timer every time your component re-renders creates a lot of repeating timers.
Your component will leave the interval timer running if the component is unmounted. It should stop the interval timer.
To fix it, pass in a function, add a dependency array, and add a cleanup callback to stop the interval:
const [activeTab, setActiveTab] = useState(0);
useEffect(() => {
const handle = setInterval(() => { // *** A function
setActiveTab(prevTab => {
if (prevTab === 3) return 0;
console.log("?ghi");
return prevTab += 1;
});
}, 1000);
return () => { // *** Clear the interval on unmount
clearInterval(handle); // ***
}; // ***
}, []); // *** Empty dependency array = only run on mount
Side note: Assuming you don't need the console.log, that state setter callback function can be simpler by using the remainder operator:
setActiveTab(prevTab => (prevTab + 1) % 3);
useEffect(() => {
setInterval(() => {
setActiveTab((prevTab) => {
if (prevTab !== 3) {
return (prevTab += 1);
} else {
return 0;
} // console.log("hi");
});
}, 1000);
}, []);

Trying to use setInterval to make a throttling function unsuccessfully

I am trying to return a function that only invokes a callback function 'func' once per every 'wait' milliseconds.
Additional calls to the callback 'func' within the 'wait' period should NOT be invoked or queued.
This is what I have so far...
function throttle(func, wait) {
function inner(...args) {
setInterval(func(...args), wait);
}
return inner;
}
When I run the code through the test algorithm I get the following errors:
"throttled functions should only be able to be called again after the specified time"
Here is the testing algorithm...
let counter = 0;
const incr = () => counter++;
const throttledIncr = throttle(incr, 32);
throttledIncr();
throttledIncr();
setTimeout(() => {
expect(counter).to.eql(1);
throttledIncr();
setTimeout(() => {
expect(counter).to.eql(2);
done();
}, 32);
}, 32);
"throttled functions return their value"
Here is the testing algorithm...
let counter = 0;
const incr = () => ++counter;
const throttledIncr = throttle(incr, 32);
const result = throttledIncr();
setTimeout(() => {
expect(result).to.eql(1);
expect(counter).to.eql(1);
done();
}, 64);
"throttled functions called repeatedly should adhere to time limitations"
Here is the testing algorithm...
const incr = () => ++counter;
const throttledIncr = throttle(incr, 64);
const results = [];
const saveResult = () => results.push(throttledIncr());
saveResult();
saveResult();
setTimeout(saveResult, 32);
setTimeout(saveResult, 80);
setTimeout(saveResult, 96);
setTimeout(saveResult, 180);
setTimeout(() => {
expect(results[0]).to.eql(1);
expect(results[1]).to.be(undefined);
expect(results[2]).to.be(undefined);
expect(results[3]).to.eql(2);
expect(results[4]).to.be(undefined);
expect(results[5]).to.eql(3);
done();
}, 192);
My questions regarding each case:
How do I prevent the function from being called again ?
Why ISNT my function returning value? I can't deduce what or how to return a value with the given testing algorithm.
What does "throttled functions called repeatedly should adhere to time limitations" even mean? This seems contradictory to the first error. There isn't any mention of setting a time limit so I don't believe using setTimeout here is what they mean...
How do I prevent the function from being called again ?
function throttle(func, wait) {
function inner(...args) {
setInterval(func(...args), wait);
}
return inner;
}
First, your code above does not do what you expect it to do. Currently every time you invoke throttle, you are adding func to the event loop, to be executed on an interval.
So when you call throttleIncr 5 times, you are adding incr to the eventloop to be called five times.
One approach (imo), would be to keep track of the last time that throttle(func) was invoked. The next time throttle(func) is invoked, check to see if the wait time has elapsed. If so, invoke func and save off the new time. If not, return.
Why ISNT my function returning value? I can't deduce what or how to return a value with the given testing algorithm.
Your incr function, IS returning the value, however your throttle function puts it on the eventloop, for asychronous execution, so the return value is not available.
What does "throttled functions called repeatedly should adhere to time limitations" even mean? This seems contradictory to the first error.
This is not a javascript error, and likely a custom failure message from the tests you are invoking.
I tried something here, that seems to be working:
function throttle2(callback, delay = 1000) {
let interval;
let currentArgs;
return (...args) => {
currentArgs = args;
if (!interval) {
interval = setInterval(() => {
if (currentArgs) {
callback(...currentArgs);
currentArgs = null;
} else {
clearInterval(interval);
interval = false;
}
}, delay);
}
};
}
Sandbox: https://codesandbox.io/s/competent-tereshkova-ccop2e?file=/index.js:167-179

call a method in a specific times in every seconds

I want to call a method 5 times in every one second. for example I have a methodA which i want to execute this method in 5 times in every 1 second. so how can i do it.
methodA(){
console.log("called")
}
timePeriod(){
setimeout....
}
You can do it with setInterval()
const test = setInterval(() => console.log("Hello method"),1000);
setTimeout( () => clearInterval(test), 5000);
Hope it is what you need!
let timePeriod = 1000 // 1000 ms
function methodA(){
console.log("called")
}
setInterval(methodA, timePeriod)
notice here that we pass the function as an argument without () which in other words we're referencing the function. Note that if you pass the function name along with () it means you're calling it independently
Also, keep in mind that setInterval works a little bit different than you might think as it's a macro task asynchronous function in the event loop. if you don't know about the event loop simply all you need to know that setInterval doesn't actually call the function unless the rest of you script gets fired + the time period you specify
setInterval = the time needed to fire the rest of the script + the time period you specify
and what you can do to test this is:
const tick = Date.now(), timeLog = (val='---') => console.log(`${val} \n Elapsed: ${Date.now() - tick} ms`)
setInterval(_ => timeLog('smth from setInterval'), 1000)
for(let i=1;i<1000000000;i++){
// this loop will run for 1B times so that we get a clear time delay
}
timeLog('smth from normal console.log')
const Comp= () => {
const methodA=()=>{
// statement here
}
useEffect(()=>{
let a = setInterval(methodA,1000/5)
return(()=>{
clearInterval(a)
},[])
})
return(<></>)
}
Try to use interval inside useEffect hook.
One could control both, the interval itself and also the condition for terminating the running interval, by writing a utility/helper function which enables not only clocked functions but also clocked methods.
function clocked(interval, isTerminate, proceed, target) {
let count = 0;
let intervalId = setInterval(() => {
proceed.call(target ?? null);
if (isTerminate(++count)) {
clearInterval(intervalId);
}
}, interval);
}
const obj = {
text: "The quick brown fox jumps over the lazy dog.",
log() {
console.log(this.text);
},
};
function doTerminateWhen(counter) {
return counter >= 5;
}
setTimeout(() => { console.log('1.001 seconds passed'); }, 1001);
clocked(200, doTerminateWhen, obj.log, obj);
setTimeout(() => { console.log('1 second passed'); }, 1000);
.as-console-wrapper { min-height: 100%!important; top: 0; }
setInterval is being used her to call the methodA function at each once second and modCall function has a for loop to iterate and call the setInterval the number of times specified in its paramter
function methodA(i){
console.log('call '+i)
}
function modCall(len){
for(let i=0;i<len;i++){
setInterval(()=>methodA(i),1000)
}
}
modCall(5) //5 is number of time you want to call the methodA

Calling a function as many times as possible in a given time interval

I am trying to call the function test() as many times as possible in a given time interval.
Here the function should be running for 15 seconds.
function test(): void; // Only type def
function run() {
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, 15000); // 15 seconds
while (true) {
test();
}
});
}
run()
.then(() => {
console.log('Ended');
});
However, the function doesn't stop running, and the Ended console.log does not appear. (Promise not resolved obviously). Is there a way to achieve this in Javascript ?
I was wondering, I could probably use console timers and put the condition in the while statement ? (But is that the best way ?)
The reason why your function does not stop executing is because resolving a promise does not stop script executing. What you want is to store a flag somewhere in your run() method, so that you can flip the flag once the promise is intended to be resolved.
See proof-of-concept below: I've shortened the period to 1.5s and added a dummy test() method just for illustration purpose:
let i = 0;
function test() {
console.log(`test: ${i++}`);
}
function run() {
return new Promise(resolve => {
let shouldInvoke = true;
setTimeout(() => {
shouldInvoke = false;
resolve();
}, 1500); // 15 seconds
const timer = setInterval(() => {
if (shouldInvoke)
test();
else
window.clearInterval(timer);
}, 0);
});
}
run()
.then(() => {
console.log('Ended');
});

Categories

Resources