3
\$\begingroup\$

I've written a general purpose repeat function which allows you to repeat a callback function X times separated by I intervals with the option to start immediately or after the interval. It can also default to just looping infinitely, which is what setInterval does. Is there a better approach, or any improvements people can provide? Make sure to comment out all but one of the examples :)

function repeatXI(callback, interval, repeat, immediate) {
 repeat = typeof repeat == 'undefined' ? -1 : repeat;
 interval = interval <= 0 ? 1000 : interval;
 immediate = typeof immediate == 'undefined' ? false : immediate;
 var offset = immediate ? 0 : 1;
 var id = null;
 if (repeat > 0) {
 for (var i = 0; i < repeat; i++) {
 id = setTimeout(callback, interval * (i + offset));
 }
 } else {
 id = setInterval(callback, interval);
 }
 return id;
}
// Example
var someFunc = function () {console.log(1);}
// Repeats forever, 1 second apart
repeatXI(someFunc, 1000);
// Repeats 10 times, 1 second apart, beginning after 1 second
repeatXI(someFunc, 1000, 10);
// Same as above, but beginning now
repeatXI(someFunc, 1000, 10, true);
asked Jun 25, 2012 at 14:45
\$\endgroup\$
1

2 Answers 2

6
\$\begingroup\$

I don't see anything problematic with your code, but just for fun, here are some alternative approaches to various parts of the code. It's 100% DRY, and functionally identical to the original.

function repeatXI(callback, interval, repeats, immediate) {
 var timer, trigger;
 trigger = function () {
 callback();
 --repeats || clearInterval(timer);
 };
 interval = interval <= 0 ? 1000 : interval; // default: 1000ms
 repeats = parseInt(repeats, 10) || 0; // default: repeat forever
 timer = setInterval(trigger, interval);
 if( !!immediate ) { // Coerce boolean
 trigger();
 }
}

And here's a jsfiddle demo

If you want, you can return timer from the function (as I do in the demo), so you can clear it (i.e. cancel the repeater) elsewhere in your code.

Regardless of the implementation-specifics it's worth noting that timers are unreliable at the best of times (since JS is single-threaded). Depending on your needs it may not be a good idea to set n timeouts at n * interval as you do for finite repeats. If a few of the timeouts get blocked long enough, they'll all queue up, and fire at once, once the thread clears. With setInterval though, you're guaranteed that there'll be at least interval time between the callbacks.

So it depends on your needs how you want to implement it.

answered Jun 25, 2012 at 19:09
\$\endgroup\$
2
  • \$\begingroup\$ good point regarding the intervals! \$\endgroup\$ Commented Jun 26, 2012 at 1:52
  • \$\begingroup\$ @AramKocharyan No prob. Don't forget to click the checkmark on mine or Joseph's answer - whichever one you think helped the most \$\endgroup\$ Commented Jun 27, 2012 at 2:03
3
\$\begingroup\$

It's pretty much commented in the code. The usage is still the same as the one you used. Here's a demo.

function repeatXI(callback, interval, repetitions, immediate) {
 //general purpose repeater function
 function repeater(repetitions) {
 if (repetitions >= 0) {
 //use call or apply so we can specify "this"
 callback.call(this);
 //repeat
 setTimeout(function() {
 //the idea of passing the repetition count replaces the loop
 //the -- means that the initial iteration turns the repeat to -1
 //since the condition runs when >=0 repetitions
 repeater(--repetitions);
 }, interval);
 }
 }
 //set defaults using ||
 //|| means "use this value OR the default"
 //if you want to be strict, you can do type checks instead
 repetitions = repetitions || 0;
 interval = interval || 1000;
 //if immediate, call instantly, else, delay
 if (immediate) {
 console.log('immediate');
 repeater(--repetitions);
 } else {
 console.log('delayed');
 setTimeout(function() {
 repeater(--repetitions);
 }, interval);
 }
}

Witout comments and packed:

function repeatXI(callback, interval, repetitions, immediate) {
 function repeater(repetitions) {
 if (repetitions >= 0) {
 callback.call(this);
 setTimeout(function () {
 repeater(--repetitions)
 }, interval)
 }
 }
 repetitions = repetitions || 0;
 interval = interval || 1000;
 if (immediate) {
 repeater(--repetitions)
 } else {
 setTimeout(function () {
 repeater(--repetitions)
 }, interval)
 }
}
answered Jun 25, 2012 at 18:55
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.