OnceLoading saved progress…

Once

You've wired up an init() that sets up listeners, opened a "Save" handler that creates a database row, or shipped an analytics call you'd be embarrassed to fire twice. once is the standard guard: it wraps a function so it runs the first time you call it and then turns into a no-op that returns the original result forever after.

Implement once(fn). It accepts any function fn and returns a new function. The first time the returned function is called, it invokes fn with the arguments you passed and remembers the return value. Every subsequent call ignores its arguments and returns the remembered value — without calling fn again.

Signature

function once(fn) {
  // returns a new function. The first call invokes fn(...args) and
  // caches the result. Every later call returns the cached result
  // without calling fn again.
}

Examples

let calls = 0;
const init = once(() => {
  calls++;
  return 'ready';
});

init(); // 'ready'  (calls === 1)
init(); // 'ready'  (calls === 1, fn was not called again)
init(); // 'ready'  (calls === 1)
const add = once((a, b) => a + b);
add(2, 3);  // 5 — fn runs with (2, 3)
add(10, 7); // 5 — args ignored, cached result returned

Notes

  • First-call args are forwarded to fn; later calls ignore whatever you pass them.
  • this binding — when the returned function is called as a method (obj.cb()), fn should see obj as this on the first call.
  • Return value is whatever fn returns, including undefined, null, or 0 — all are valid cached results.
  • One-shot — the second call must not invoke fn, even with different arguments.
  • Don't rebuild the cache state across instances. Each call to once(fn) creates a fresh, independent wrapper.
Loading editor…