having trouble using setInterval and with random number generation - javascript

I'm trying to create a random quote generator. I have created a function called timer that runs another function pickQuote every 400ms but at the moment this doesn't seem to work. in pickQuote I run a function randomNumberGen that creates a random number. My problem in the randomNumberGen is that I want to have an if or if..else in place that checks whether or not the new random number is different from the current quotes[randomNumber] but i'm unsure how to do this.
Can anyone provide me with some insight on how I can achieve this?
My current effort can be viewed here: http://jsbin.com/aqinud/12/edit

index is not defined outside $.each. Variables in functions are not accessible outside it if you use var.
What I recommend is altering the function as follows:
function randomNumberGen() {
//generate randomNumber based on length of array
// round it down (parseInt is for string->number conversion)
var thisRandomNumber = Math.floor(Math.random() * len);
if ( randomNumber === thisRandomNumber ) {
randomNumberGen();
} else {
randomNumber = thisRandomNumber;
}
}
So, first create a random number and only if it's different from randomNumber, update it with the newly created one. Otherwise, try again.
Also, setTimeout requires a function, so don't invoke it yet:
runQuotePicker = setInterval(pickQuote, 400);
http://jsbin.com/aqinud/13/edit

Perhaps something like this:
var currentNumber = -1;
function randomNumberGen() {
var num = parseInt(Math.random() * (len) );
if(currentNumber != num){
currentNumber = num;
return num;
} else {
return randomNumberGen();
}
}
I noticed you had incorrectly passed 'pickQuote' to setInterval. Try wrapping the callback in an anonymous function:
function timer() {
runQuotePicker = setInterval(function(){
pickQuote();
}, 1000);
}
Otherwise you're scheduling the result of pickQuote to be invoked ever x milliseconds.

Related

setInterval array variable is not working in Js

I am new to JS.
I need an array variable which is used to display the values periodically every 1s using setInterval() inside a function.
The array variable for ex intV[] (setInterval variable) should display the values when used in console.log(intV[]); and the values should be stored in intV[].
I tried the below code,
But it didn't work.
function date() {
var currentDate = Date.now();
var val = String(currentDate).substr(8, 2);
return val;
}
var intV = [];
function mockData(v) {
var v = document.getElementById('sample');
//setInterval function
intV[v] = setInterval(date, 1000);
console.log(intV[v]);
}
When I did console.log(intV[v]);. It doesn't display the values every 1s. Instead, it gives a static value Which is not updated every 1s.
How could i store the values, which is updated every 1s in the intV[].?
Could someone please help?
Many thanks.
The setInterval method expects a function as a parameter which is run at each specified interval. All of the logic, including console.log needs to be inside of the function that you pass to setInterval. I believe the sample provided below provides what you are looking for, but you need to understand that the intV array will be populated AS the intervals occur, NOT before.
var intV = [];
function date() {
var currentDate = Date.now();
var val = String(currentDate).substr(8, 2);
intV.push(val);
console.log(intV[intV.length - 1])
}
//setInterval function
setInterval(date, 1000);

Send variable to the same function

I want a function that looks for elements with the "comment" class, and if the number of comments has changed, (if there is a new comment) it will call an other function. So this is what I did:
function main(num0){
var comments = document.getElementsByClassName("comment");
var num = comments.length;
if (num!=num0){
//function to call();
console.log("New Comment");
}
setTimeout(main(num),10); //check every 10 for new comments
}
main(0);
num0 is the number of comments the last time the function was called so I try to recall the same function but num0 takes the value of num, but it doesn't seems to work.
I recommend using setInterval. calling recursion at higher rate may cause different errors after some time.
let num = 0;
setInterval(()=>{
var comments = document.getElementsByClassName("comment");
var num1 = comments.length;
if (num!=num1){
//function to call();
console.log("New Comment");
num=num1
}
},10)
Your use of setTimeout is invalid; you are calling the function main instead of providing setTimeout with a callback. I also believe you need to pass num0 instead of num in your timeout.
Try this:
function main(num0){
var comments = document.getElementsByClassName("comment");
var num = comments.length;
if (num!=num0){
//function to call();
console.log("New Comment");
}
setTimeout(main, 10, num0); // Changed this line
}
main(0);
Review this regarding the setTimeout function:
https://www.w3schools.com/jsref/met_win_settimeout.asp
setTimeout takes a function reference. In your case you aren't passing the reference, you are passing the result of that function by calling it.
Example of syntax that does what you intend it to do:
setTimeout(() => main(num),10); //check every 10 for new comments
https://www.w3schools.com/jsref/met_win_settimeout.asp

Javascript: Loop through Array with Delay

I am trying to loop through an array, but want to output each value of the array with a delay. This is what my current understanding is on how it should work:
EDIT
Requested JS Fiddle: http://jsfiddle.net/d3whkjww/
loopThroughSplittedText: function(splittedText) {
for (var i = 0; i < splittedText.length; i++) {
// for each iteration console.log a word
// and make a pause after it
setTimeout(
console.log(splittedText[i]),
1000
);
};
},
Yet, it does not work, and I believe it might be, because the arguments in the "for" loop have to be inside the setTimeout function. Yet I don't know how to make it work.
All I get is every value of the array at once, but I want them appear with a delay. How do I do that?
var splittedText = ["Hello", "World", "How", "Are", "You", "Today"];
function loopThroughSplittedText(splittedText) {
for (var i = 0; i < splittedText.length; i++) {
// for each iteration console.log a word
// and make a pause after it
(function (i) {
setTimeout(function () {
document.getElementById('text').innerHTML += splittedText[i];
console.log(splittedText[i]);
}, 1000 * i);
})(i);
};
}
loopThroughSplittedText(splittedText);
Fiddle Demo
Chances are you're going to want to use a recursive function instead of a for loop here. However, I'll explain both ways just in case you (or someone else reading this) has your heart set on doing this with a loop.
For a recursive function, the general idea is that you'll want to call the function once, then let it call itself repeatedly until it's finished doing what you want it to do. In terms of code, it will could look something a bit like this:
loopThroughSplittedText: function(splittedText) {
// Create our counter; delayedOutput will use this to
// track how far along in our string we are currently at
var locationInString = 0;
function delayedOutput() {
// Output the next letter in our string
console.log(splittedText[locationInString]);
// Increment our counter so that on the next call we are on the next letter
locationInString++;
// Only perform setTimeout if we still have text left to output
if (locationInString < splittedText.length) {
// Functions can reference themselves using their own name
setTimeout(delayedOutput, 1000);
}
}
// Call our function once to get things started
delayedOutput();
},
Alternatively, if you really prefer using a loop, you can still do it, but there's a fair bit of fiddling that has to be done to accomplish this.
First, you're going to need to place console.log within its own function. This is because when you place console.log(something), you're not actually passing it, but calling it right then and there, which is not what you want; by calling it, it spits out the text to the console right away rather than waiting until later. Tucking it away in its own function allows it to be passed to setTimeout so it can be called later on.
Second, you're going to have to wrap that function in yet another function to ensure that it's given the correct value of i when it fires. The reason is effectively this: Your intention is to tell the function "when you're ready, use what i was when I set you up." However, what you're doing right now is effectively saying "when you're ready, look at i". Because the function doesn't check what i is until it's ready to fire, it won't know its value until long after you have performed the loop, meaning i will be a number much higher than you want!
As a bit of a sub-point to the above, you'll want to call that function immediately. This is known as an immediately invoked function expression. If you're not familiar with them, they're certainly worth looking up. Their uses are a bit unusual, but they're a powerful tool in the right spot.
Finally, because you're setting up everything right here and now, you want to make sure the timeout for each function is a second apart; as it stands now, you're saying "do all of these one second from now", when your intention is "do all of these one second apart, starting one second from now". This fix is relatively easy; all you need to do is multiply your timeout by i so that you set up the first to go 1 second from now, the second to go 2 seconds from now, and so on.
All of that combined gives you code that looks something like this:
loopThroughSplittedText: function(splittedText) {
for (var i = 0; i < splittedText.length; i++) {
setTimeout(
(function(locationInString) {
return function() {
console.log(splittedText[locationInString]);
};
}(i)),
(1000*i)
);
}
},
As for which solution is better, I would probably recommend the recursive function. The recursive version will only create one function that calls itself for every string you pass it, whereas the for loop version will create one function for every character in the string, which could get out of hand very quickly. Function creation (and object creation in general) can get expensive in JavaScript when you're working on larger projects, so it's generally best to favor solutions that avoid creating massive amounts of functions when possible.
But still, for sake of explanation, I wouldn't want to leave you without the for loop version; the knowledge could come in handy in other places. :)
A recursive function call would do the job:
var a = [
1,2,3,4,5,6,7,8,9,10
];
function log(i){
console.log(a[i]);
if (i<a.length){
setTimeout(function(){
i++;
log(i);
},1000);
}
}
log(0);
http://jsfiddle.net/Curt/rjve4whe/1/
In my example, it will show you how to loop through an array contentiously until you stop. This is to just give you an idea on how you can do the delay. Also it shows you when the value actually got displayed.
I would say that you could actually create a nice utility from this timer, and use it for multiple purposes and with the utility it'll stop you from repeating large chunks of code.
JavaScript Loop example:
var body = document.body;
var splittedText = ["Hello", "World", "How", "Are", "You", "Today"];
loopThroughArray(splittedText, function (arrayElement, loopTime) {
body.innerHTML += arrayElement+ ": " + loopTime+ "<br/>";
}, 1000);
function loopThroughArray(array, callback, interval) {
var newLoopTimer = new LoopTimer(function (time) {
var element = array.shift();
callback(element, time - start);
array.push(element);
}, interval);
var start = newLoopTimer.start();
};
// Timer
function LoopTimer(render, interval) {
var timeout;
var lastTime;
this.start = startLoop;
this.stop = stopLoop;
// Start Loop
function startLoop() {
timeout = setTimeout(createLoop, 0);
lastTime = Date.now();
return lastTime;
}
// Stop Loop
function stopLoop() {
clearTimeout(timeout);
return lastTime;
}
// The actual loop
function createLoop() {
var thisTime = Date.now();
var loopTime = thisTime - lastTime;
var delay = Math.max(interval - loopTime, 0);
timeout = setTimeout(createLoop, delay);
lastTime = thisTime + delay;
render(thisTime);
}
}
Ok, as It is not an exact duplicate, you need to increate the delay in the loop, also escape from the closure variable in a loop issue
loopThroughSplittedText: function (splittedText) {
splittedText.forEach(function (text, i) {
setTimeout(function () {
console.log(text);
}, i * 1000)
})
}
var obj = {
loopThroughSplittedText: function(splittedText) {
splittedText.forEach(function(text, i) {
setTimeout(function() {
document.getElementById('x').innerHTML += text
}, i * 1000)
})
}
}
obj.loopThroughSplittedText('abcde'.split(''))
<div id="x"></div>
One problem with your code is that i is common to all the callbacks. So the first callback is told "output the entry at index i", however by the time it gets to execute the initial loop is finished so i is now at the end of the text.
One way to achieve what you're looking for is to not use a for loop, but to have a function which (1) prints a character, (2) updates the counter/position, and (3) schedules the next character if needed:
loopThroughSplitText: function (text) {
var i = 0;
function printEntry() {
console.log(text[i]);
i++; // Increment the position
if (i < text.length) { // If there are more chars, schedule another
setTimeout(printEntry, 1000);
}
}
printEntry(); // Print the first entry/char
}
solution using closure
https://jsfiddle.net/x3azn/pan2oc9y/4/
function loopThroughSplittedText(splittedText) {
var splittedText = ["Hello", "World", "How", "Are", "You", "Today"];
for (var i = 0; i < splittedText.length; i++) {
// for each iteration console.log a word
// and make a pause after it
(function(_i) {
setTimeout(function() {
window.document.getElementById('text').innerHTML = splittedText[_i];
console.log(splittedText[_i]);
}, 1000)
}(i));
}
}
loopThroughSplittedText()
One more solution, with a setInterval:
var i = 0;
var intv = setInterval(function() {
if (i >= splittedText.length) {
clearInterval(intv);
} else {
console.log(splittedText[i]);
++i;
}
}, 1000);
There are a couple of problems here
setTimeout should take a function, not the result of calling a function
setTimeout returns immediately, so all the actions in your loop will be started at roughly the same moment, and all wait 1000ms before execting (notwithstanding the comment above however, which means they're all executed at the same moment).
The value of i will all be equal to splittedText.length for each iteration due to not wrapping your loop control variable in a closure.
What you need to do, is wait until the setTimeout instructions are executed before moving on to the next iteration of the loop.
For example:
var splittedText = ["Hello", "World", "How", "Are", "You", "Today"];
function loopThroughSplittedText(splittedText) {
displayValue(splittedText,0);
}
function displayValue(arr, i){
if(i<arr.length){
setTimeout(function(){
document.getElementById('text').innerHTML = arr[i];
console.log(arr[i])
displayValue(arr,i+1);
},1000)
}
}
loopThroughSplittedText(splittedText)
Live example: http://jsfiddle.net/d3whkjww/1/
This will also work
function loopThroughSplittedText(splittedText) {
for (var i=0; i < splittedText.length;i++) {
(function(ind, text) {
setTimeout(function(){console.log(text);}, 1000 + (1000 * ind));
})(i, splittedText[i]);
}
}
Another sample:
var split = 'Lorem ipsum dolor'.split(' ');
var loop = function() {
console.log(split[0]);
split = split.slice(1);
if (split.length > 0) {
setTimeout(function() {
loop();
}, 1000);
}
}
loop();
Bringing out an alternative solution to the problem, which is making use of the third argument to setTimeout which is only supported in newer browsers:
(function (splittedText) {
for (var i = 0; i < splittedText.length; i++) {
setTimeout(
function(val) { console.log(val); },
i * 1000,
splittedText[i]
);
}
})(["Hello", "world", "!"]);
API documentation can be seen here (note the optional params).
You can achieve by 3 ways
1. closure
2. Recursive
3. variable declaration using let
var data = ['a', 'b', 'c', 'd'];
closure:
for(i=0; i<=data.length; i++) {
(function(x) {
setTimeout(() => {
console.log(x);
}, 1000)
})(data[i]);
}
let variable declaration
for(const ind of data) {
let local = ind;
setTimeout(() => {
console.log(local);
}, 1000)
}

Timing in JS - multiple setIntervals running at once and starting at the same time?

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>

setInterval(setTimeout) function for given invokes javascript

I need to invoke some function given number of times through given delays. How should I do - declare variable for timer and pass it to invoking function for stopping timer in some moment or in loop (n times) invoke setTimeout once ( or some another approach to skeep delay time once) or other.Thanks.
edit to fix syntax eror
var timerID = null;
var n = 5;
this.timerID = setInterval(function(){
funcToInvoke(n,timerID){
if(invokeNumber == n){
clearInterval(timerID);
return;
}
else { do something}
}
},delay)
Yes, the approach is common and better than calling setTimeout in a loop (with a fixed number of times). It is more performant than that and also more flexible, because the interval will be stopped dynamically (might check for a future condition).
However, your code is a bit messy. Fixed:
// Assuming we a have
// n
// delay
// funcToInvoke
// and execute in context of some object
var that = this,
numberOfInvokes = 0;
this.timer = setInterval(function() {
// "this" points to the global object
if (numberOfInvokes == n)
clearInterval(that.timer);
else
funcToInvoke(numberOfInvokes);
numberOfInvokes++;
}, delay);
Your current method has a syntax problem, you can't have a function parameter like this.timerID). In fact, you should remove the whole funcToInvoke declaration, and declare n and timerID as local variables, so they will be available to the closure. Like this:
// Don't forget to define n here!
var n = 5;
// Change timerID to local var instead of property
var timerID = null;
timerID = setInterval(function(){
if(invokeNumber == n){
clearInterval(timerID);
return;
} else {
//do something
}
// You can setTimeout again anywhere in this function if needed
}, delay);
If you want an approximate delay, setInterval is probably ok. If you want a more precise interval, then repeated calls to setTimeout are better as you can adjust the length of time to the next call based on the time since the last call.
E.g. for a clock ticking every second, you can do repeated calls to setTimeout, setting the lag to just after the next full second.

Categories

Resources