I'm looping through a set of images within an array of animation frames. There are 7 images, and looping from 1-7 pletes the animation. I need this animation to loop indefinitely, but I was wondering which of these is the best approach:
Loop by modifying array
/* Pull image from start of array. */
var image = frames.shift();
/* Process image. */
...
/* Add image back to end of array. */
frames.push(image );
Loop using counter variable
/* Pull image by counter offset. */
var image = frames[counter];
/* Process image. */
...
/* Increment or reset counter value. */
counter + 1 === frames.length ? counter = 0 : counter = counter + 1;
Is there a reason I'd chose one over the other? Alternatively, is there a better approach to this?
I'm looping through a set of images within an array of animation frames. There are 7 images, and looping from 1-7 pletes the animation. I need this animation to loop indefinitely, but I was wondering which of these is the best approach:
Loop by modifying array
/* Pull image from start of array. */
var image = frames.shift();
/* Process image. */
...
/* Add image back to end of array. */
frames.push(image );
Loop using counter variable
/* Pull image by counter offset. */
var image = frames[counter];
/* Process image. */
...
/* Increment or reset counter value. */
counter + 1 === frames.length ? counter = 0 : counter = counter + 1;
Is there a reason I'd chose one over the other? Alternatively, is there a better approach to this?
Share Improve this question asked Apr 6, 2013 at 21:42 James DonnellyJames Donnelly 129k35 gold badges214 silver badges223 bronze badges 4-
4
I'd use
counter % frames.length
. Array operations are rather heavy andshift
causes the array items' indexes to be re-enumerated, while a property lookup is quite cheap. – Fabrício Matté Commented Apr 6, 2013 at 21:45 -
FWIW, you can loop around with the counter using the modulus operator:
counter = (counter + 1) % frames.length;
edit: What Fabrício said ;) – Felix Kling Commented Apr 6, 2013 at 21:45 - Ah I hadn't considered modulus at all. How simple! – James Donnelly Commented Apr 6, 2013 at 21:53
-
If you felt like being fancy, you could loop over them once and say
image.next = frames[(i + 1) % frames.length];
. Then in your animation just hold on to the last image you processed, and say something likeimage = image.next;
and never bother with arrays or counters again... :) – cHao Commented Apr 6, 2013 at 21:57
3 Answers
Reset to default 5Modifying the array is going to be more expensive than simply using a variable to keep track of your position in the array. The better way to do this, if you're looping indefinitely, seems to just be to use a while
loop (rather than using a for
loop where you reset the counter inside):
var i = 0;
while (true) {
doSomething to array[i];
i = (i+1) % array.length;
}
However if your goal really is having an animation proceed indefinitely every time a given interval elapses, a loop isn't ideal at all. Use setInterval
instead.
var frames = ...; //your images
var i = 0;
function animate() {
do something to frames[i];
i = (i+1) % array.length;
}
setInterval(animate, time_between_runs);
where time_between_runs
is how much time should elapse before the function is called again.
Alternatively a circular linked list also can be used I think. To turn an array of objects into a circular linked list:
frames.forEach(function(elem, index) {
elem.next = frames[index + 1] || frames[0];
});
And now you can do something like this:
setInterval(function() {
frame = frame.next;
....
}, delay);
One possibility is to ditch the array and use a linked list.
Make each frame an object that points to the next object. The last one then points to the first. Then all you need to do is reference the next object.
var curr = first; // reference to first frame object
setInterval(function() {
// process image
curr.image.doSomething();
// proceed to next
curr = curr.next;
}, 1000);
No counters to mess with this way.
Setting up the linked list is usually pretty simple, and can likely be done with just a little modification to the current code that's setting up the Array.
var first = new Frame(); // This is your entry point
var current = first; // This holds the current frame during setup
for (var i = 0; i < totalFrames; i++) {
current.next = new Frame(); // Make the current reference a new frame
current = current.next; // Make the new frame current
}
current.next = first; // circular reference back to the first.
function Frame() {
// set up this frame
}
Then first
is your starting point.
Or the linking could be done within the Frame
constructor.
var first = new Frame(null);
var current = first;
for (var i = 0; i < totalFrames; i++) {
current = new Frame(current);
}
current.next = first;
function Frame(currFrame) {
// link this frame to the given one
if (currFrame)
currFrame.next = this;
// set up the rest of this frame
}