30

Is there a way to run a piece of JavaScript code only ONCE, without using boolean flag variables to remember whether it has already been ran or not?

Specifically not something like:

var alreadyRan = false;
function runOnce() {
  if (alreadyRan) {
    return;
  }
  alreadyRan = true;

  /* do stuff here */

}

I'm going to have a lot of these types of functions and keeping all booleans would be messy...

5
  • 2
    You need to clarify the question a bit more. Commented Sep 9, 2010 at 16:43
  • But people will call if more than once and I want the counters to only activate once. Commented Sep 9, 2010 at 16:47
  • Maybe you should edit your question and clarify what this is about. You have functions as event handlers that you only want to have called once? Commented Sep 9, 2010 at 16:48
  • 9
    not a bad question once you understand it. Commented Sep 9, 2010 at 16:58
  • Dan is this homework? Explain where are you trying to apply this, or else the answers will never serve your need. Commented Sep 9, 2010 at 20:19

9 Answers 9

75

An alternative way that overwrites a function when executed so it will be executed only once.

function useThisFunctionOnce(){
   // overwrite this function, so it will be executed only once
   useThisFunctionOnce = Function("");
   // real code below
   alert("Hi!");
}

// displays "Hi!"
useThisFunctionOnce();
// does nothing
useThisFunctionOnce();

'Useful' example:

var preferences = {};
function read_preferences(){
   // read preferences once
   read_preferences = Function("");
   // load preferences from storage and save it in 'preferences'
}
function readPreference(pref_name){
    read_prefences();
    return preferences.hasOwnProperty(pref_name) ? preferences[pref_name] : '';
}
if(readPreference('like_javascript') != 'yes'){
   alert("What's wrong wth you?!");
}
alert(readPreference('is_stupid') ? "Stupid!" : ":)");

Edit: as CMS pointed out, just overwriting the old function with function(){} will create a closure in which old variables still exist. To work around that problem, function(){} is replaced by Function(""). This will create an empty function in the global scope, avoiding a closure.

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

14 Comments

+1 indeed! Putting a new meaning to "this function will self-destruct after first use".
very neat though I fail to see the value of this. though that's not your fault +1
I've added an example for mcgrailm :)
I've given you an answer on your question "Run a code once without using booleans". If this does not answer your question, please provide a code example with your current situation, the problem and the desired situation.
I would strongly discourage the usage of this pattern, because all variables, arguments, and inner FunctionDeclarations of the first function, will be never be garbage collected, this might not be obvious, but it's true, the empty function is created within the first one, this creates a closure, and all identifiers will remain live, creating a memory leak. I would recommend either, declare the empty function outside, or use the Function constructor, e.g. useThisFunctionOnce = Function("");. Try this test to see how effectively all variables remain in-scope.
|
9

I like Lekensteyn's implementation, but you could also just have one variable to store what functions have run. The code below should run "runOnce", and "runAgain" both one time. It's still booleans, but it sounds like you just don't want lots of variables.

var runFunctions = {};

function runOnce() {
  if(!hasRun(arguments.callee)) {
   /* do stuff here */
   console.log("once");
  }
}

function runAgain() {
  if(!hasRun(arguments.callee)) {
   /* do stuff here */
   console.log("again");
  }
}


function hasRun(functionName) {
 functionName = functionName.toString();
 functionName = functionName.substr('function '.length);
 functionName = functionName.substr(0, functionName.indexOf('('));

 if(runFunctions[functionName]) {
   return true;
 } else {
   runFunctions[functionName] = true;
   return false;
 }
}

runOnce();
runAgain();
runAgain();

5 Comments

(Note: I still like Lekensteyn's implementation better)
Three lines for parsing the function name is kinda heavy. I recommend a simple regexp solution: functionName = func.toString().match(/\w+(?=\()/)[0]
@Mike Robinson - Why is there two function definitions for runAgain()?
@bennedich - I like the idea of a regex, but the one you supplied doesn't work, and returns "function" when I fix it
@Mike That's fair enough. I was actually unsure whether it was somehow part of the trickery - wasn't trying to be a smart ass ;-)
8

A problem with quite a few of these approaches is that they depend on function names to work: Mike's approach will fail if you create a function with "x = function() ..." and Lekensteyn's approach will fail if you set x = useThisFunctionOnce before useThisFunctionOnce is called.

I would recommend using Russ's closure approach if you want it run right away or the approach taken by Underscore.js if you want to delay execution:

function once(func) {
    var ran = false, memo;
    return function() {
        if (ran) return memo;
        ran = true;
        return memo = func.apply(this, arguments);
    };
}

var myFunction = once(function() {
    return new Date().toString();
});

setInterval(function() {console.log(myFunction());}, 1000);

On the first execution, the inner function is executed and the results are returned. On subsequent runs, the original result object is returned.

4 Comments

I've been trying to understand Underscore's once and I'm confused. On the second call, isn't ran re-declared and initialized to false, thereby calling func.apply() a second time?
@Seabiscuit once returns the inner function and run was defined in the outer function. The result is a closure where run and memo are shared by all calls to the function.
I imagined that's how that worked. What I still don't get is how (and here I'm admitting my ignorance of how closures work at a deep level) when the call is made to once(func) the variable assignment in the outer function, namely ran = false does not affect the value of ran in the return function. Since every call to once(func) invokes the outer and inner functions, then ran = false is assigned every time once(func) is called.
@Seabiscuit Closures are created any time a function is called and a function in its scope outlives it. If I call once twice, I get two closures each with their own ran value. If I call the returned functions, they set run = true in their own closure scope and don't interfere with each other.
6

What about an immediately invoked anonymous function?

(function () {

    // code in here to run once

})();

the code will execute immediately and leave no trace in the global namespace.

If this code is going to need to be called from elsewhere, then a closure can be used to ensure that the contents of a function are run only once. Personally, I prefer this to a function that rewrites itself as I feel doing so can cause confusion, but to each their own :) This particular implementation takes advantage of the fact that 0 is a falsy value.

var once = (function() {
  var hasRun = 0;  
  return function () {
    if (!hasRun) {
      hasRun++;   

      // body to run only once

      // log to the console for a test       
      console.log("only ran once");
    }              
  }
})();

// test that the body of the function executes only once
for (var i = 0; i < 5; i++) 
  once();

Comments

3

Elegant solution from Douglas Crockford, spent some time to understand how it works and stumbled upon this thread.

So the wrapper once return function which is just invokes parameter's function you passed. And taking advantage of closures this construction replaced passed function to empty function, or null in original source, after the first call, so all the next calls will be useless.

This is something very close to all other answers, but it is kinda self containing code and you could use it independently, which is good. I am still trying to grasp all the entire mechanism of replacement, but practically it just works perfectly.

function once (func) {

 return function () {
   var f = func;
   func = null;
   return f.apply(this, arguments);
 };

}

function hi(name) {
  console.log("Hi %s", name);
}

sayonce = once(hi);
sayonce("Vasya");
sayonce("Petya");

for those who are curious here is jsbin transformations

Comments

1
(function (){

  var run = (function (){

    var func, blank = function () {};

    func = function () {
      func = blank;

      // following code executes only once 
      console.log('run once !');
    };

    return function(){
      func.call();
    };
  })();

  run();
  run();
  run();
  run();

})();

Comments

1

I just ran into this problem, and ended up doing something like the following:

function runOnce () {
    if (!this.alreadyRan) {
        // put all your functionality here
        console.log('running my function!');

        // set a property on the function itself to prevent it being run again
        this.alreadyRan = true;
    }
}

This takes advantage of the fact that Javascript properties are undefined by default.

Comments

0

In addition, the nature of what happens in the "/* do stuff here */" may leave something around that, when present, must mean that the function has run e.g.

var counter = null;

function initCounter() {
  if (counter === null) {
    counter = 0;
  }
}

Comments

-2

If not bound to an event, code is usually ran once

1 Comment

simple enough, considering the question.

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.