0

I am trying to get my head around the various techniques that can be used to avoid the use of global variables in JavaScript.

Consider the following code, that performs a redirect to a URL after a countdown timer:

var _redirectTimer;
function startRedirectTimer() {
    clearTimeout(_redirectTimer);

    var redirectTimer = function(timeLeft) {
    if(timeLeft == 0) {
        // redirect to application path
        var redirectURL = window.location.protocol+"//"+window.location.host + "/" + location.pathname.split("/")[1];
        window.location.replace(redirectURL);
        return;
    } else {
        timeLeft--;
        _redirectTimer = setTimeout(function () {redirectTimer(timeLeft)}, 1000);
    }   
}   
redirectTimer(60);  

}

My client code only ever calls startRedirectTimer(). However, _redirectTimer is a global variable that I'd rather not expose. Ideally, I'd like this variable to be a "state" variable within startRedirectTimer(), similar to how you'd have a private method in a singleton java class. Can someone advise on how I can achieve this?

Thanks

2 Answers 2

1

Well, the quick way around variables is just wrapping an extra function around the section in question:

(function()
{//wrapper function
    var _redirectTimer;
    function startRedirectTimer()
    {
        clearTimeout(_redirectTimer);
        var redirectTimer = function(timeLeft) {
        if(timeLeft == 0)
        {
            // redirect to application path
            var redirectURL = window.location.protocol+"//"+window.location.host + "/" + location.pathname.split("/")[1];
            window.location.replace(redirectURL);
            return;
        }
        else
        {
            timeLeft--;
            _redirectTimer = setTimeout(function () {redirectTimer(timeLeft)}, 1000);
        }   
    }   
    redirectTimer(60);  
})();//call wrapper function

As always, you can choose when to call the timeout function by exposing it to the global object. However, if I understood correctly you're looking for a way to contain the _redirectTimer or link that to the startRedirectTimer function somehow (obviously without it loosing its state after each call). This is possible, in a number of ways:

function startRedirectTimer()
{
    //as you would, only: add this line
    var _redirectTimer = startRedirectTimer._redirectTimer;
}
startRedirectTimer._redirectTimer;//functions are objects, so assign properties and methods at will

These properties and methods live as long as the function, so their values aren't reset after each call. Downside: they're publicly accessible, and can be redefined by accident.
Closures are the best fit for cases like this:

var startRedirectTimer = (function()
{
    var _redirectTimer,timeLeft = 60;//initial value here
    var redirectURL = window.location.protocol+"//"+window.location.host + "/" + location.pathname.split("/")[1];//
    return function ()
    {
        clearTimeout(_redirectTimer);
        if (timeLeft === 0)
        {
            return window.location.replace(redirectURL);
        }
        timeLeft--;
        _redirectTimer = setTimeout(startRedirectTimer,1000);//just call the main function again
    }
})();//return value of this function will be the actual startRedirectTimer function

To set things in motion with the code above, just call startRedirectTimer() once, and it should work. It's untested code, this, and I'm a bit feverish today, but it should. IMO, less code, and more efficient.

Sign up to request clarification or add additional context in comments.

2 Comments

Almost there, one thing....I do not want clearTimeout() to be called every time. Only when startRedirectTimer is first invoked, but not on the recursive call. Your first solution seems to work best
_redirectTimer is undefined on the first call, so clearing it doesn't really do anything. clearing it on every other call should prevent the timout to stick to 1 second intervals when you accidentally call the function twice. not sure if I quite see what it is you're trying to do
0

You can enclose it in a closure:

(function() {
    var _redirectTimer, redirectTimer;
    window.redirectTimer = redirectTimer = function() {
        // ......
    }
    redirectTimer(60);
})();

If you don't need redirectTimer outside this closure, you can remove the window.redirectTimer = part.

3 Comments

How do I invoke startRedirectTimer() then? I only need to invoke this method, but it in turn needs to invoke redirectTimer()
Hold on, it looks like I mis-read some of your code. It seems kind of redundant, why can't you just set a timer for 60 seconds and redirect afterwards?
@Kolink, I've noticed that, too but I think the OP wants to implement some sort of count-down system

Your Answer

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.