2

Hey guys can someone just quickly help me out here.

I have an interval for a slideshow in one function and I want to clear it from another function without using global scopes as I know it is bad practice.

Can someone kindly help here please?

function beginSlideshow() {
    var interval = setInterval(function () {
      //Slideshow content here
}

function revertSlideshow() {
    clearInterval(interval);
}
justaguy
  • 51
  • 5
  • 4
    Don't make `interval` local to `beginSlideshow()`? – Dave Newton Nov 08 '21 at 16:35
  • 1
    I've been told making it global is bad practice – justaguy Nov 08 '21 at 16:36
  • Isn't that a form of global scope? – justaguy Nov 08 '21 at 16:37
  • There are tightly scoped variables (like your `interval` here, that's available only inside one function), there are global variables (window.interval), but there are also in-between scopes. You don't have to go all white or all black – Jeremy Thille Nov 08 '21 at 16:38
  • You could use a scoping function, take a look at [this answer](https://stackoverflow.com/a/5786899/16688813) – Tom Nov 08 '21 at 16:38
  • It's "bad practice" in the *general* sense--but there are already two global references here (the functions), so... There are multiple options, e.g., wrapping these functions in an IIFE that returns the two functions, keeping `interval`'s scope to that IIFE. – Dave Newton Nov 08 '21 at 16:40
  • You have to pull `interval` out of `beginSlideshow()`. Since `beginSlideshow()` is at the root, that makes it a global variable, so, necessarily, `interval` will have to be a global variable too. If you don't want global variables (that's a good idea), encapsulate the whole thing in another function, or better yet, in a class. – Jeremy Thille Nov 08 '21 at 16:40
  • Encapsulation in a class in another option, although w/o a "bunch" of related functionality it seems like a lot of ceremony for not a lot of benefit. (Not that JS has "classes" in the common sense anyway :) – Dave Newton Nov 08 '21 at 16:43

1 Answers1

6

You have to store the timer handle somewhere. :-)

You have lots of options:

Modules

You could use modules. Then a top-level declaration of interval wouldn't be a global, it would only be accessible to the module:

let interval = 0;
export function beginSlideshow() {
    interval = setInterval(function () {
        //Slideshow content here
    }, someValue);
}

export function revertSlideshow() {
    clearInterval(interval);
    interval = 0;
}

In a closure's scope

Similar concept to the module above, but without using modules:

const { beginSlideshow, revertSlideshow } = (() => {
    let interval = 0;
    function beginSlideshow() {
        interval = setInterval(function () {
            //Slideshow content here
        }, someValue);
    }

    function revertSlideshow() {
        clearInterval(interval);
        interval = 0;
    }

    return { beginSlideshow, revertSlideshow };
})());

In the caller's scope

You could make this the problem of the person calling beginSlideshow by returning the function to stop it:

function beginSlideshow() {
    const interval = setInterval(function () {
        //Slideshow content here
    }, someValue);
    return () => {
        clearInterval(interval);
    };
}

The caller would use that like this:

const revertSlideshow = beginSlideShow();
// ...
revertSlideshow();

Another way to store it in the caller's scope is to wrap this up in a class and have the handle be a data property:

class Slideshow {
    interval = 0;

    begin() {
        this.interval = setInterval(/*...*/);
    }

    revert() { // I'd call it "end"
        clearInterval(this.interval);
        this.interval = 0;
    }
}
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875