here is my pseudo code
var list = {
a:[
{content: 'a', time: 5},
{content: 'b', time:2},
{content: 'c', time:3}]
}
var insert_and_stop = function(content, time){
//let content insert to somewhere and wait for "time" second
}
my requirement is running a loop to insertSome(content, time) on dataset(list)
and start over again to the head of list
obviously, I can use for to run my function on list
but I don't know how to start over?
Sorry for incomplete code
Update !!!
my solution right now is:
for(var i = 0; i<list.a.length; i++){
(function(i){
setTimeout(insert(list.a[i].content), list.a[i].time * 1000);
})(i);
}
it works but i don't if I let while(true) include this code
the browser will crash because the for... part will run repeatly
I think what pid meant to say in his answer is that you should use:
setInterval(function, delay)
Where function is the function name and delay is the delay in milliseconds between invocations.
Using your code as a reference and your query, here is how I would approach it:
var list = {
a:[
{content: 'a', time: 5},
{content: 'b', time:2},
{content: 'c', time:3}]
}
var i = 0;
var insertContent = function(){
// Do something with the content
console.log(list.a[i].content);
// Either increment the i or restart at 0.
if((list.a.length - 1) > i ){
i++;
}else{
i = 0;
}
setTimeout(function(){
// Run the function again
insertContent();
}, list.a[i].time * 1000);
}
This code will loop until the end of the array and then starts again.
I have tested it on my side and seems to be working, however I did rename the function, so just adapt it according to your requirements.
The two options here are setInterval(function, delay) and setTimeout(function, delay). The main difference being, that setInterval will fire exactly each delay time period, while setTimeout will only fire when the internal code has been run. In practice, you would have to look out for side effects in case of code that runs for longer than you'd expect (and that would cause setInterval to stack the code on top of itself multiple times).
Examples:
function myTimeoutFunc(){
// .. some code
setTimeout(myFunc, delay-in-milliseconds);
}
myFunc();
function myIntervalFunc(){
// .. some code
}
setInterval(myIntervalFunc, delay-in-milliseconds);
Use setInterval(<function-name>, <delay-in-milliseconds>) where <function-name> is the function name or a lambda (if you know what this is) and <delay-in-milliseconds> is the delay in milliseconds between invocations.
Otherwise, if you actually need to do it inside insert_and_stop() you can do as follows. Write an actual function (this means you need just 1 exit point). Then, just before you exit your function:
setTimeout(function () { insert_and_stop(content, time); }, time);
You need the lambda (the wrapping function) because the parameters content and time need to be passed correctly for the subsequent invocations.
Note that this will not invoke your function every <time> milliseconds because the execution time of the function itself is not accounted for. If insert_and_stop() takes a time that is similar to <time> this effect might become sensible. Otherwise, if the function is quick (microseconds) and the interval is high (100 or 1000 times as long) then the overhead may be negligible, based on what you are actually doing.
//set my function each 3seconds
var interval = setInterval("myFunction", 3000);
//or
var interval = setInterval(function(){
alert("I am myFunction");
}, 3000);
//release
releaseInterval(interval);
It's important "setInterval" return value that needs to release!
Related
I have succeeded in cobbling together pieces of code that achieve my goal. However, I would like some advice from more advanced vanilla JS programmers on how I can go about reaching my goal in a better way.
To start, I want to introduce my problem. I have a piece of text on my website where a portion is designed to change every so often. For this, I am running through a loop of phrases. To run this loop continuously, I first call the loop, then I call it again with setInterval timed to start when the initial loop ends. Here is the code I've got, which works even if it isn't what could be considered quality code:
function loop(){
for (let i = 0; i < header_phrases.length; i++){
(function (i) {
setTimeout(function(){
header_txt.textContent = header_phrases[i];
}, 3000 * i);
})(i);
};
}
loop();
setInterval(loop, 21000);
Is there a better way to right this code for both performance and quality? Do I need to use async? If so, any material I can see to learn more? Thanks!
You can implement the same logic using recursion.
function recursify(phrases, index = 0) {
header_txt.textContent = phrases[index];
setTimeout(function () {
recursify(phrases, index < phrases.length - 1 ? index + 1 : 0);
}, 300)
}
recursify(header_phrases);
The function 'recursify' will call itself after 300 miliseconds, but everytime this function gets called, the value of index will be different.
If I understand your requirement correctly, you want top populate an element from an array of values.
A simple way to do this is:
doLoop();
function doLoop() {
var phraseNo=0;
setTimeout(next,21000);
next();
function next() {
header_txt.textContent = header_phrases[phraseNo++];
if(phraseNo>=header_phrases.length) phraseNo=0;
}
}
This simply puts the next() function on the queue and waits.
The call to next() before the function simply starts it off without waiting for the timeout.
this is assuming that header_txt and header_phrases are not global vars. using global vars isn't a good idea.
var repeatIn = 3000;
phraseUpdater();
function phraseUpdater() {
var updateCount = 0,
phrasesCount = header_phrases.length;
setHeader();
setTimeout(setHeader, repeatIn);
function setHeader() {
header_txt.textContent = header_phrases[updateCount++ % phrasesCount] || '';
}
}
I want a function I am writing to call itself automatically. I want to be able to parse the frequency at which it calls itself via the first time I parse it. It would then use that same value internally with the JS setTimeout() function to call itself repeatedly again at the same frequency.
So you can see what I have in the sample below:
function testFunction(refreshFrequ){
setTimeout(function() {
console.log("frequency: "+refreshFrequ);
testFunction(refreshFrequ);
}, refreshFrequ);
}
// run the 1st time
testFunction(5000);
The problem is that this doesn't work as from the second time it runs onwards the parsed timeout isn't evaluated. The console output gives a clue to what's going on here:
frequency: undefined
How would I get this working, nothing so far has helped.
Try Window setInterval() Method instead. Also see this answer and this answer for more information.
var autoInterval;
var elapsed = 0;
function myStartFunction(refreshFrequ) {
if (!autoInterval) {
autoInterval = setInterval(function() {
elapsed++;
document.getElementById("txt").innerHTML = refreshFrequ * elapsed + " elapsed.";
console.log("frequency interval: " + refreshFrequ + " x " + elapsed);
}, refreshFrequ);
}
}
function myStopFunction() {
if (autoInterval) {
clearInterval(autoInterval);
autoInterval = null;
elapsed = 0;
document.getElementById("txt").innerHTML = "Interval was reset.";
console.log("interval stopped");
}
}
myStartFunction(5000);
<p>The setInterval() method has started automatically.</p>
<button onclick="myStartFunction(1000)" title="Start with 1000 ms interval. Clicking this button while the event is active should not create a new interval instance.">Start</button> <button onclick="myStopFunction()" title="Click to stop and clear the interval instance.">Stop</button>
<p id="txt">0 elapsed.</p>
Edit: Although there was no mention of the potential duplicate function calls, the other answer should be taken into consideration, especially if the event can arbitrarily be executed. The if statement was imposed in order to prevent duplicate events from being stacked up against the original instance; otherwise, each additionally executed function would result in a unique instance, which could then further create unstoppable multiple events, so I must give credit where credit is due. Kudos to Tymek!
You might want to use setInterval instead.
var testFunction = (function () { // This will "build"/"enclose" our function
var handle = null; // ID of the interval
return function (freq) {
if (handle !== null) clearInterval(handle);
handle = setInterval(function() {
console.log("frequency: " + freq);
}, freq);
};
})();
With this if you re-initialize interval, you will not create another instance of it (having 2 functions ticking).
You can learn more about setInterval at: https://www.w3schools.com/jsref/met_win_setinterval.asp
and more about how JavaScript functions works at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
Let's say I have a function:
myFunc = function(number) {
console.log("Booyah! "+number);
}
And I want it to run on a set interval. Sounds like I should use setInterval, huh!
But what if I want to run multiple intervals of the same function, all starting at the exact same time?
setInterval(function(){
myFunc(1);
}, 500);
setInterval(function(){
myFunc(2);
}, 1000);
setInterval(function(){
myFunc(3);
}, 2000);
So that the first runs exactly twice in the time it takes the second to run once, and the same between the second and third.
How do you make sure that they all start at the same time so that they are in sync?
Good question, but in JS you can't. To have multiple functions in the same program execute at the same time you need multi-threading and some deep timing and thread handling skills. JS is single threaded. setInterval doesn't acutally run the function after the delay, rather after the delay it adds the function to the event stack to be run as soon as the processor can get to it. If the proc is busy with another operation, it will take longer than the delay period to actually run. Multiple intervals/timeouts are all adding calls to the same event stack, so they run in turn as the proc is available.
function Timer(funct, delayMs, times)
{
if(times==undefined)
{
times=-1;
}
if(delayMs==undefined)
{
delayMs=10;
}
this.funct=funct;
var times=times;
var timesCount=0;
var ticks = (delayMs/10)|0;
var count=0;
Timer.instances.push(this);
this.tick = function()
{
if(count>=ticks)
{
this.funct();
count=0;
if(times>-1)
{
timesCount++;
if(timesCount>=times)
{
this.stop();
}
}
}
count++;
};
this.stop=function()
{
var index = Timer.instances.indexOf(this);
Timer.instances.splice(index, 1);
};
}
Timer.instances=[];
Timer.ontick=function()
{
for(var i in Timer.instances)
{
Timer.instances[i].tick();
}
};
window.setInterval(Timer.ontick, 10);
And to use it:
function onTick()
{
window.alert('test');
}
function onTick2()
{
window.alert('test2');
}
var timer = new Timer(onTick, 2000,-1);
var timer = new Timer(onTick2, 16000,-1);
For a finite number of ticks, change the last parameter to a positive integer for number. I used -1 to indicate continuous running.
Ignore anyone who tells you that you can't. You can make it do just about any thing you like!
You can make something like this.
arr = Array();
arr[0] = "hi";
arr[1] = "bye";
setTimer0 = setInterval(function(id){
console.log(arr[id])
},1000,(0));
setTimer1 = setInterval(function(id){
console.log(arr[id]);
},500,(1));
Hope it helps!
JavaScript is single threaded. You can use html5 web worker or try using setTimeout recursively. Create multiple functions following this example:
var interval = setTimeout(appendDateToBody, 5000);
function appendDateToBody() {
document.body.appendChild(
document.createTextNode(new Date() + " "));
interval = setTimeout(appendDateToBody, 5000);
}
Read this article:
http://weblogs.asp.net/bleroy/archive/2009/05/14/setinterval-is-moderately-evil.aspx
You can use multiples of ticks inside functions, in the example below you can run one function every 0.1 sec, and another every 1 sec.
Obviously, the timing will go wrong if functions require longer times than the intervals you set. You might need to experiment with the values to make them work or tolerate the incorrect timing.
Set a variable to handle tick multiples
let tickDivider = -1
Increase the value of tick variable inside the faster function
const fastFunc = ()=> {
tickDivider += 1
console.log('fastFunciton')
}
Use a condition to on running the slower function
const slowFunc = ()=> {
if (!(tickDivider % 10)){
console.log('slowFunction')
}
}
Call both functions in a single one. The order is not important unless you set tickDivider to 0 (of any multiple of 10)
const updateAllFuncs = () => {
fastFunc()
slowFunc()
}
Set the interval to the frequency of the faster function
setInterval(updateAllFuncs, 100)
What I'm doing here is adding a speed attribute to the HTML elements. These speeds are passed as a parameter to setCounter(). I did this mainly to make the code easier to test and play with.
The function setCounter() is invoked inside a loop for every HTML element with class counter. This function sets a new setInterval in every execution.
The intervals seem to be working in sync.
const elements = document.querySelectorAll('.counter')
elements.forEach((el, i) => {
let speed = Number(elements[i].getAttribute('speed'))
setCounter(el, speed, 5000)
})
function setCounter(element, speed, elapse){
let count = 0
setInterval(() => {
count = (count >= elapse) ? elapse : count + speed
if(count === elapse) clearInterval()
element.innerHTML = count
}, 1)
}
Same Speeds
<p class="counter" speed='10'></p>
<p class="counter" speed='10'></p>
Different Speeds
<p class="counter" speed='3'></p>
<p class="counter" speed='5'></p>
I have function called rotator(id): this function animate div and I can called this function with different id for animate different elements
Actually I use 5 differents id , 1,2,3,4,5
And for call I need put :
rotador(1);rotador(2);rotador(3);rotador(4);rotador(5);
The problem it´s that I want to rotate in automatic mode. For this I think to use this
for (i=0;i<=5;i++) {
setTimeout(rotador(i),2000);
}
But it doesn't work because it animates all in the same time, no let firt execute the first and continue before of first go second , etc , etc and when go the end or number 5 start other time in one
My problem it´s this if you can help me THANKS !!! :) Regards
You are actually calling the rodator(i) function, and schedule for execution after 2 seconds the result of the rodator. In other words, your code is now equalent to:
for (i=0;i<=5;i++) {
var result = rotador(i);
setTimeout(result,2000);
}
You can accomplish this either by creating a function for the callback:
for (i=0;i<=5;i++) {
setTimeout((function(i){
return function(){
rotador(i);
}
})(i),2000 * i);
}
or you can call the next rodator in the rotador function itself:
var rotador = function(i){
// your code
if (i < 5) {
setTimeout(function(){rotaror(i + 1);}, 2000);
}
}
Note: the closure in the second example is needed to call the function with the correct value of i. We are creating an anonymous function, and create i as a local scope variable, which value won't be mutated by the outerscope changes. (we can rename i to n in the local scope, if this would be more readable). Otherwise the value of i will be 5 each time rotador is called, as the value of i would be modified before the actual function call.
since setTimeout() does not wait for the function to be executed before continuing, you have to set the delay to a different value for different items, something like 2000 * (i + 1) instead of just 2000
EDIT: yes, and you need the callback as Darhazer suggests
rotationStep(1);
function rotador(id)
{
console.log(id);
}
function rotationStep( currentId )
{
rotador(currentId);
var nextId = currentId<5 ? currentId+1 : 1;
setTimeout(function(){ rotationStep(nextId) },2000); //anonymous function is a way to pass parameter in IE
}
Use a callback:
setTimeout(function() {
rotador(i)
}, 2000)
So.. I have a webpage with a javascript function I wish to execute..
Not knowing javascript very well I exectue the function through the url bar..
javascript: Myfunct1();
javascript: Myfunct2();
Now what I really need to be able to do is a long sleep, execute the first function, sleep for a little, then execute the second function, then loop forever.. something like:
javascript: while(1) { Sleep(20000); Myfunct1(); Sleep(5000); Myfunct2() };
Obviously there isn't a 'Sleep' function.. and this is my problem.. After looking at various posts about 'setTimeout;, I tried that but have been unable to get it right.. was wondering if somebody would take pitty and a poor javascript simpleton and show me the way to do this?
have a look at setTimeout(). This will give you the delay you're looking for.
http://www.w3schools.com/js/js_timing.asp
Just pop this into your HTML before the </body> tag
<script type="text/javascript"><!--
setTimeout(function(){
Myfunct1();
setTimeout(function(){
Myfunct2();
},5000);
},20000);
--></script>
You can use setInterval in conjuction with setTimeout function:
setTimeout('Myfunct1(); setInterval("Myfunct1();", 25000);', 20000);
setTimeout('Myfunct2(); setInterval("Myfunct2();", 25000);', 25000);
This will accomplish the functionality like in your example without hanging the browser. Basicallly, it will Myfunct1() after 20s, and set it to run again 25s after that. Same thing is with Myfunct2(), except that it first run after 25s.
Here's a function that allows you to call alternating functions, waiting a specified amount of time between each invocation:
function alt(fn1, tm1, fn2, tm2) {
var curr, time;
(function next() {
curr = (curr === fn1) ? fn2 : fn1;
time = (time === tm1) ? tm2 : tm1;
window.setTimeout(function() {
curr();
next();
}, time);
})();
}
Use it like this:
alt(Myfunct1, 20000,
Myfunct2, 5000);
This will wait 20 seconds, then call Myfunct1, then wait 5 seconds and call Myfunct2, then wait 20 seconds and call Myfunct1 again, and so on.
Here's a general purpose version that accepts any number of function/timeout pairs:
function alt() {
var args = arguments;
(function next(i) {
if (i == args.length)
i = 0;
window.setTimeout(function() {
args[i]();
next(i + 2);
}, args[i + 1]);
})(0);
}
It's used the same way, but can accept more than two pairs:
alt(function(){console.log("1")}, 2000,
function(){console.log("2")}, 1000,
function(){console.log("3")}, 5000);
If this were real code there's a lot more you could do, like verify arguments and/or specify default timeouts when not provided for any of the given functions.