I want to cycle through an array and display each element individually, and then remove it. Sort of like this fiddle, but I don't want it to go forever.
I tried using jQuery because I thought it would be easier, but I am clearly missing something. Can anyone help?
Here is my attempt, but it just goes straight to the last element in the array.
var list = [1,2,3,4,5,6];
var length = list.length;
for(i = 0; i < length; i++) {
$('#nums').html(list[i]).delay(750);
}
Oh, and I don't care if it's jQuery or vanilla JavaScript. Either is fine by me.
$(document).ready(function(){
var list = [1,2,3,4,5,6];
var length = list.length;
var i = 0;
var ivl = setInterval( function () {
if (i < length) {
$('#nums').html(list[i]).delay(750);
i++;
}
else {
clearInterval(ivl);
}
}, 750);
});
The (pretty clever) example uses the fact that the modulus operator (%) gives you remainder, which is periodic, so you can use it to cycle through your array by taking the remainder of an infinitely increasing number divided by the length of your list.
If you want it to stop, however, you can just do a check to see if you've finished cycling through the list:
var list = [1, 2, 3, 4, 5, 6];
var length = list.length;
var i = 0;
var finished = false;
function repeat() {
if (!finished) {
document.getElementById('nums').innerHTML = list[i % length];
i++;
if (i === length) {
finished = true;
}
} else {
clearInterval(interval);
}
}
var interval = setInterval(repeat, 750);
<div id="nums"></div>
Late to the party but wouldn't it be better to use setTimeout rather than setInterval just in case the code executed on each iteration takes longer than the interval duration? I mean, I know it's not an issue in this instance but it's just a better/safer way to do this sort of thing.
$(document).ready(function(){
var list = [1,2,3,4,5,6];
var length = list.length;
var i = 0;
(function next(){
if (i < length){
$('#nums').html(list[i++]);
setTimeout(next,750);
}
})();
});
http://jsfiddle.net/zLexhdfp/3/
Related
I'm trying to make a dice roller using JavaScript, and want the dice to cycle through a few values, and visually show these, before stopping on a final number.
I'm however having trouble with getting innerHTML to work as intended.
The code I'm running
function test() {
var testArray = [3, 4, 5, 6, 7, 8];
for (var i = 0; i < testArray.length; i++) {
container.innerHTML = testArray[i];
sleep(50);
}
}
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
}
Whenever I run the test() function it wont visually cycle through the array and only shows the last number of the array on the HTML page.
I have tried to use the setTimeout function, and gotten the same results, I have also tried setting the delay time higher.
You should use setInterval in order to give the browser a chance to update the window.
The problem here is that JavaScript is single-threaded. And for most browsers, this thread is also used to update the UI. Because of that, your window will not be updated until the script is completely finished.
Using setInterval pushes the function onto the queue to be executed at a later point after the running script has finished and the UI had time to update.
var container = document.getElementById('container');
test();
function test() {
var testArray = [3, 4, 5, 6, 7, 8];
var i = 0;
var interval = setInterval(function () {
if (i >= testArray.length - 1) {
clearInterval(interval);
}
container.innerHTML = testArray[i];
i++;
}, 50);
}
<div id="container"></div>
I ask this question again as user Cerbrus have marked the previous question as a duplicate of this question.
Can someone be so kind to show me how the question indicated by this user, should solve the code below? I can't find a match between those situations (even thought they are similar).
I need to pass a variable to a function inside a for loop. Here's an example:
var mainObj = [],
subArr = ['val1', 'val2'],
tmp;
for (var i = 0; i < subArr.length; i++) {
tmp = subArr[i];
mainObj.push({
key: function(varsFromLibrary) {
myFunc(tmp);
}
});
}
Here I have 2 problems:
why do i have to assign subArr[i] to tmp? Using myFunc(subArr[i]) will return that i is undefined?
why in myFunc i only receive the last value of subArr array?
UPDATE
I've updated the code as follows but i get TypeError: funcs[j] is not a function
var mainObj = [],
subArr = ['val1', 'val2'],
tmp,
funcs = [];
function createfunc(i) {
return function() { console.log("My value: " + i); };
}
for (var i = 0; i < subArr.length; i++) {
funcs[i] = createfunc(subArr[i]);
}
for (var j = 0; j < subArr.length; j++) {
tmp = subArr[i];
mainObj.push({
key: function(varsFromLibrary) {
funcs[j]();
}
});
}
Simply use let :
for (var i = 0; i < subArr.length; i++) {
let tmp = subArr[i];
mainObj.push({
key: function(varsFromLibrary) {
myFunc(tmp);
}
});
}
Or why cant you simply copy the value into the object?:
for (var i = 0; i < subArr.length; i++) {
mainObj.push({
tmp:subArr[i],
key: function(varsFromLibrary) {
myFunc(this.tmp);
}
});
}
Another try of explaining:
Lets imagine youre a byciclist. You want to measure your speed so you ask 10 friends of you to stand next to the route at certain points and to tell you your speed. Some pseudocode:
const friends = [];
var speed = 20;//youre really fast
for(var point = 1; point < 10; point++){
speed -= 2;//youre slowing down
friends.push({
ask(){
console.log(point, speed);
}
});
}
Now afterwards you stand at the last point 10 together with your friends and you ask them for the current speed and the point they stay at. What will they tell you? Exactly, they are all standing next to you at point 10 and your current speed is 0. You asked them for the current speed and not to remember the current speed. If you want them to remember it, they need to write it down:
friends.push({
speed,//every friend object has the current value stored
point,
ask(){ console.log(this.speed,this.point)}
});
Or you need to create 10 parallel universes your friends stay in, so if you ask them for your speed they will still see you driving next to them:
for(let point = 1; point < 10; point++){
let localspeed = (speed -= 2);//youre slowing down
why do i have to assign subArr[i] to tmp?
You don't. That isn't the solution proposed by the duplicate question.
Using myFunc(subArr[i]) will return that i is undefined?
i won't be undefined. It will be the same as subArr.length.
subArr[i] will be undefined, because subArr.length is the number of items in the array and the array is zero indexed.
why in myFunc i only receive the last value of subArr array?
Because that is the last value you copied to tmp before the loop ended.
As the high rated answer on the question you link to says, you need to copy i or subArr[i] to a new scope so it won't change next time you go around the loop.
I have a simple setInterval function that is done inside of a for loop. My goal is that I want the function to run on each position in the array, and once it reaches the end, I want it to stop. However, this is not happening. The timeout function is continuing to run infinitely. Can anyone explain where I'm going wrong and what I need to do to fix this?
JS
Keyhole.bufferArray = [Keyhole.twoMileBuffer, Keyhole.fiveMileBuffer, Keyhole.tenMileBuffer, Keyhole.twentyFiveMileBuffer];
var ticker = -1;
for(var i = 0; i < Keyhole.bufferArray.length; i++){
var populateServices = setInterval(function(){
++ticker;
addBuffersToService(Keyhole, i);
if(ticker >= Keyhole.bufferArray.length - 1){
ticker = -1;
clearInterval(populateServices);
}
}, 1000)
}
function addBuffersToService(Keyhole, index){
console.log(Keyhole);
}
Because you have a for loop that is making an interval for every index of the array. You should not be using the for loop if you are looping over the array with the interval. Remove the for loop.
The problem is that you overwrite your interval handler in loop. I suggest you to kepp handlers in array and remove them according to iterator varialble:
var ticker = -1;
var populateServices = [];
for(var i = 0; i < Keyhole.bufferArray.length; i++){
populateServices[ticker + 1] = setInterval(function(){
...
clearInterval(populateServices[ticker + 1]);
ticker = -1;
Note that array identifiers should be positive numbers so you should add +1 inside handlers array.
And don't forget to set ticker to -1 after clearInterval invokation.
My Javascript timer is for people with a rubiks cube with generates a scramble (nevermind all this, but just to tell you I'm generating after each solve a new scramble will be generated) and my scrambles do actually have a while (true) statement. So that does crash my script, but it 95/100 times stops just before the script crashes but I don't wanna have any times.
Let me explain a bit more detailed about the problem.
Problem: javascript crashes because my script takes too long to generate a scramble.
Below you have 3 functions I use.
This function generates a scramble with the Fisher-Yates shuffle.
Timer.prototype.generateScramble = function(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
};
This function validates the input e.g. I receive an array as the following:
Here I only have to check the first character. That's why I use the seconds [ ] notation. I don't want people get an F with an F2 e.g.
var scr = ["F","R","U","B","L","D","F2","R2","U2","B2","L2","D2","F'","R'","U'","B'","L'","D'"]
Timer.prototype.validateScramble2 = function(array) {
var last = array.length-1;
for (var i = 0; i < array.length-1; i++) {
if (array[i][0] == array[i+1][0]) {
return false;
}
}
for (var i = 0; i < array.length-2; i++) {
if (array[i][0] == array[i+2][0]) {
return false;
}
}
if (array[0][0] == [last][0]) {
return false;
}
return true;
};
The above functions are just waiting to be called. Well in the function below I use them.
Timer.prototype.updateScramble2 = function(scrambleArr, len, type) {
var self = this;
var scramble = '', j, updatedArr = [];
while (updatedArr.length < len) {
j = (Math.floor(Math.random() * scrambleArr.length));
updatedArr.push(scrambleArr[j]);
}
while (!self.validateScramble2(updatedArr)) {
updatedArr = self.generateScramble(updatedArr);
}
for (var i = 0; i < updatedArr.length; i++) {
scramble += updatedArr[i] + ' ';
}
scrambleDiv.innerHTML = scramble;
};
I assume you guys understand it but let me explain it briefly.
The first while-loop adds a random value from the given array(scrambleArr) into a new array called updatedArr.
The next while-loop calls the validateScramble2() function if there isn't in an array F next to an F2.
The for-loop adds them into a new variable added with a whitespace and then later we show the scramble in the div: scrambleDiv.innerHTML = scramble;
What do I need know after all this information?
Well I wanna know why my updateScramble2() functions lets my browser crash every time and what I do wrong and how I should do it.
I'm not entirely sure I understand the question, but from the way your code looks, I think you have an infinite loop going on. It appears as if validateScramble2 always returns false which causes your second loop in updateScramble2 to perpetually run.
I suggest you insert a breakpoint in your code and inspect the values. You could also insert debugger; statements in your code, works the same way. Open dev tools prior to doing these.
A suggestion is instead of using loops, use a timer. This breaks up your loop into asynchronous iterations rather than synchronous. This allows the browser breathing space for other operations. Here's an example of a forEachAsync:
function forEachAsync(array, callback){
var i = 0;
var timer = setInterval(function(){
callback.call(null, array[i]);
if(++i >= array.length) clearInterval(timer);
}, 0);
}
forEachAsync([1,2,4], function(item){
console.log(item);
});
You can take this further and use Promises instead of callbacks.
for (var i=list.length; i>=0; i--){
//do something....
}
I want to use a setInterval to make this process take 1 whole min no matter how many items are in the list. So if there are 10 items it would trigger every 6sec, 30items, every two seconds, etc.
Thanks for any help!
Something like this could be done:
var list = [1,2,3,4,5,6,7,8,9,10];
var timeFrame = 60000;
var interval = timeFrame / (list.length-1);
var i = 0;
(function iterate () {
if (list.length > i) {
console.log(list[i]);
i++;
}
setTimeout(iterate, interval);
})();
JsFiddle Demo
I am not sure if this is what you're looking for, but this will "iterate" through all items in the list, without using for loop, in the given timeframe. The function will always "call itself" using setTimeout. The timeout is calculated in the beginning based on the number of items.
This solution is much more "trustable" than setInterval. The next timeout will be set when the previous action is already done, so it won't stack up.
var totalItem = list.length;
setInterval(function(){ alert('');}, 60000/totalItem);
You'd do
function code(i) {
return function() { alert(i); };
}
var period = 60 * 1000 / (list.length - 1);
for (var i=list.length; i>=1; i--){
setTimeout(code(list[i - 1]), period * (i - 1));
}
Try something like the following:
var interval = 2;
for (var i=list.length; i>=0; i--){
setTimeout(your_code_here(), i*interval);
}