mirror of
https://github.com/discordjs/discord.js.git
synced 2026-09-17 08:47:27 +00:00
fix(util): cache nullish values in lazy() (#11564)
lazy() used defaultValue ??= cb(), so a callback returning null or undefined was never cached and re-ran on every call, breaking the compute-once contract (any side effect in the callback repeated). Track a called flag instead of relying on value nullishness.
This commit is contained in:
@@ -29,4 +29,28 @@ describe('lazy', () => {
|
||||
expect(callback).toHaveBeenCalledOnce();
|
||||
expect(cachedValue).toEqual('Lorem Ipsum');
|
||||
});
|
||||
|
||||
test('GIVEN undefined callback with cached value THEN returns the same', () => {
|
||||
const callback = vi.fn<() => string | undefined>(() => undefined);
|
||||
|
||||
const lazyStoredValue = lazy(callback);
|
||||
|
||||
lazyStoredValue();
|
||||
const cachedValue = lazyStoredValue();
|
||||
|
||||
expect(callback).toHaveBeenCalledOnce();
|
||||
expect(cachedValue).toBeUndefined();
|
||||
});
|
||||
|
||||
test('GIVEN null callback with cached value THEN returns the same', () => {
|
||||
const callback = vi.fn(() => null);
|
||||
|
||||
const lazyStoredValue = lazy(callback);
|
||||
|
||||
lazyStoredValue();
|
||||
const cachedValue = lazyStoredValue();
|
||||
|
||||
expect(callback).toHaveBeenCalledOnce();
|
||||
expect(cachedValue).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,6 +13,11 @@
|
||||
// eslint-disable-next-line promise/prefer-await-to-callbacks
|
||||
export function lazy<Value>(cb: () => Value): () => Value {
|
||||
let defaultValue: Value;
|
||||
// eslint-disable-next-line promise/prefer-await-to-callbacks
|
||||
return () => (defaultValue ??= cb());
|
||||
let called = false;
|
||||
return () => {
|
||||
if (called) return defaultValue;
|
||||
called = true;
|
||||
// eslint-disable-next-line promise/prefer-await-to-callbacks
|
||||
return (defaultValue = cb());
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user