Once
Prompt
Implement a function once that takes a callback function as an argument and returns a new function. The returned function should invoke the callback only on the first call. All subsequent calls should return the result of the first invocation without calling the callback again.
Playground
You need a way to remember whether the callback has already been called. A boolean variable in a closure can track this.
Don't forget to store the result of the first call. On subsequent calls, you should return that stored result without invoking the callback again.
Solution
Explanation
This is a closure question. We need two variables that persist across multiple calls to the returned function: called (has the callback already run?) and result (what did it return?).
The returned function checks called on every invocation. The first time, called is false, so we run the callback, store its return value in result, and flip called to true. Every subsequent call sees called is true, skips the callback entirely, and just returns the stored result.
function once(callback) {
let called = false;
let result;
return function (...args) {
if (!called) {
called = true;
result = callback(...args);
}
return result;
};
}The reason this works is closures. The inner function "closes over" called and result. Even though once has already finished executing, those two variables stay alive because the returned function still references them. Each call to once creates its own separate called and result, so multiple once-wrapped functions don't interfere with each other.
Notice that we store and return the result. This is important. If someone writes:
const getConfig = once(() => loadExpensiveConfig());
const config1 = getConfig(); // calls loadExpensiveConfig()
const config2 = getConfig(); // returns cached result, no second loadBoth config1 and config2 get the same value. The expensive operation only runs once, but the result is available every time. This is actually a simple form of memoization, specific to functions with no arguments.
Where once is used in practice
- Initialization logic: database connections, SDK setup, config loading. You want it to happen exactly once.
- Event handlers: sometimes you want a button click to do something only the first time.
- Lodash:
_.once()does exactly this.