How to stop a javascript function from within another function?

14,920

Solution 1

It looks to me like you actually want to stop the rotate() function, rather then commence, since rotate is what is actually changing the images (ie running the slideshow).

There are two ways. The first, like thriqon posted, is to use the clearTimeout function. However I'd recommend doing it like this:

// somewhere in global space
var rotateTimeout;

// in commence
rotateTimeout = window.setInterval(rotate,4000); // this will tell the browser to call rotate every 4 seconds, saving the ID of the interval into rotateTimeout

// in stopSlide
window.clearInterval(rotateTimeout); // this will tell the browser to clear, or stop running, the interval.

The second, which is a bit messier, is to use a sentinel.

// somewhere in global space
var running;

// in commence
running = true;
rotate();

// in stopSlide
running = false;

// in rotate
if (running) {
    setTimeout(rotate,4000);
}

Solution 2

You want to use window.clearTimeout using the id you get by call window.setTimeout.

But you should also consider switching to window.setInterval, which gives you an function call every 4 seconds (and not 4 seconds after the last call), the not-needing of repeated calls to re-set the timeout and a better handling of missed events.

See this jsFiddle: http://jsfiddle.net/D3kMG/ for an example on how to use these functions for a simple counter.

Share:
14,920
BartoszKP
Author by

BartoszKP

I like TDD and clean architectures with clean code inside. My first language was C++, learned when I was young. After I started working as a software engineer there was a lot of switching between C++ and .NET/C#, and thus I really like both languages. I also like Python very much, and have some experience. I had also a very brief period using Java, and a lot of small encounters with languages like Prolog, Fortran, and Lisp. Later I was working as a SCRUM master and then as an architect and supervisor of multiple SCRUM teams. In 2018 I've been working with hearing instruments at Sonova WSC as a .NET Software Engineer. Since 2019 I'm working at Google.

Updated on June 04, 2022

Comments

  • BartoszKP
    BartoszKP almost 2 years

    I'm developing a simple slideshow system. I've got the slideshow wrapped in a hidden div, which is shown when a thumbnail from the gallery is clicked.

    The slideshow works through a function called commence(), which is executed when the play button is clicked.

    At the moment I've got it set to hide to whole div again when stop is clicked, but I would like to keep the div shown, simply stop the slideshow, in other words, stop the commence() function.

    Can anyone tell me how to do this?

    Here is my JS:

    function commence() {
        hidden = document.getElementById("hidden");
        hidden.style.display = 'block';
        pause = document.getElementById("pause");
        pause.style.display = 'block';
        play = document.getElementById("play");
        play.style.display = 'none';
        pic = document.getElementById("picbox"); // Assign var pic to the html element.
        imgs = []; // Assign images as values and indexes to imgs array.
    
    /* --------------------------- IMAGE URLS FOR IMGS ARRAY -------------------------*/
    
        imgs[0] = "/snakelane/assets/images/thumb/_1.jpg";  imgs[10] = "/snakelane/assets/images/thumb/_19.jpg"; 
        imgs[1] = "/snakelane/assets/images/thumb/_2.jpg";  imgs[11] = "/snakelane/assets/images/thumb/_20.jpg"; 
        imgs[2] = "/snakelane/assets/images/thumb/_3.jpg";  imgs[12] = "/snakelane/assets/images/thumb/_21.jpg";
        imgs[3] = "/snakelane/assets/images/thumb/_4.jpg";  imgs[13] = "/snakelane/assets/images/thumb/_22.jpg";
        imgs[4] = "/snakelane/assets/images/thumb/_5.jpg";  imgs[14] = "/snakelane/assets/images/thumb/_23.jpg";    
        imgs[5] = "/snakelane/assets/images/thumb/_6.jpg";  imgs[15] = "/snakelane/assets/images/thumb/_24.jpg";
        imgs[6] = "/snakelane/assets/images/thumb/_7.jpg";  imgs[16] = "/snakelane/assets/images/thumb/_25.jpg";
        imgs[7] = "/snakelane/assets/images/thumb/_8.jpg";  imgs[17] = "/snakelane/assets/images/thumb/_26.jpg"; 
        imgs[8] = "/snakelane/assets/images/thumb/_9.jpg";  imgs[18] = "/snakelane/assets/images/thumb/_27.jpg";
        imgs[9] = "/snakelane/assets/images/thumb/_10.jpg"; imgs[19] = "/snakelane/assets/images/thumb/_28.jpg"; 
    
    
    /* -----------------------------------------------------------------------------------------------------*/
    
    
        var preload = []; // New array to hold the 'new' images.
        for(i = 0 ; i < imgs.length; i++) // Loop through imgs array
        {
            preload[i] = new Image(); // Loop preload array and declare current index as a new image object.
            preload[i].src = imgs[i]; // Fill preload array with the images being looped from ims array.
        }
        i = 0; // Reset counter to 0.
        rotate(); // Execute rotate function to create slideshow effect.
    }
    
    // Function to perform change between pictures.
    function rotate() {
        pic.src = imgs[i]; // Change html element source to looping images
        (i === (imgs.length -1))?(i=0) : (i++); // counter equals imgs array length -1.
        setTimeout( rotate, 4000); // Sets the time between picture changes. (5000 milliseconds).
    }
    
    
    function init() {
    
        [].forEach.call(document.querySelectorAll('.pic'), function(el) { 
            el.addEventListener('click', changeSource); 
        });
    
    
        function changeSource() {  
            hidden = document.getElementById("hidden");
            hidden.style.display = 'block';
            newpic = this.src; 
            var pic = document.getElementById("picbox");
            pic.src = newpic;
        }
    }
    
    document.addEventListener("DOMContentLoaded", init, false);
    
    function stopSlide() {
        var hidden = document.getElementById("hidden");
        hidden.style.visibility = 'hidden';
        pause.style.display = 'none';
        var play = document.getElementById("play");
        play.style.display = 'block';
    }
    

    The pause and play statements are not relevant to my question, they simply hide the play button and show the pause button if the slideshow is running, and vice versa.

    • Sushanth --
      Sushanth -- over 10 years
      Use a return statement
    • bfavaretto
      bfavaretto over 10 years
      Looks like what you need to stop is the setTimeout in rotate.
    • Admin
      Admin over 10 years
      Thanks! how do I do that? can I stop the timeout with a statement in the stopSlide() function?
    • bfavaretto
      bfavaretto over 10 years
      Actually, every time rotate runs, a new call is scheduled (via setTimeout). So you just need an if to decide whether to schedule a new call or not. I don't know what the condition should be, though.
  • thriqon
    thriqon over 10 years
    One small annotation: This kind of code is not multithread-safe! If multiple threads were active at the same time, it could happen to actually lose the stop signal. But normally, JS in the browser is one thread at a time.