Skip to content

Instantly share code, notes, and snippets.

@peat-psuwit
Created May 19, 2022 18:00
Show Gist options
  • Save peat-psuwit/d880af168215174a2ad92c1b4182f06c to your computer and use it in GitHub Desktop.
Save peat-psuwit/d880af168215174a2ad92c1b4182f06c to your computer and use it in GitHub Desktop.
function bindWeakImpl<
TFn extends (...args: any) => any,
TTarget extends object,
>(fn: TFn, weakTarget: WeakRef<TTarget>, defaultReturn: ReturnType<TFn>)
{
return function(...args: Parameters<TFn>): ReturnType<TFn> {
const target = weakTarget.deref();
if (target === undefined) {
console.debug(`bindWeak: target of ${fn} is now unreachable. Return ${defaultReturn}`);
return defaultReturn;
}
return fn.call(target, args);
}
}
function bindWeak<
TFn extends (this: TTarget, ...args: any) => any,
TTarget extends object,
>(fn: TFn, target: TTarget, defaultReturn: ReturnType<TFn>) {
const weakTarget = new WeakRef(target);
// Why need impl, you asked? Because if we return an anonymous function from right here, it
// _could_ hold a reference to the target despite not using it, defeating the use of WeakRef.
// Even though we don't actually refer to the target inside this function, better be safe than
// sorry. See https://blog.meteor.com/an-interesting-kind-of-javascript-memory-leak-8b47d2e7f156
return bindWeakImpl(fn, weakTarget, defaultReturn);
}
// Demo time!
class Native {
// Imagine that this clas is actually e.g. a Gobject-introspection object.
// The cb field below would then be a GC root, preventing gabarge collection.
cb?: (x: number) => void;
setCb(cb: (x: number) => void) {
this.cb = cb;
}
}
class Wrapper {
native: Native;
constructor() {
this.native = new Native();
// If nothing else refers to Wrapper, since the reference in this cb is weak, Wrapper
// can be collected, and so does the Native object and this cb.
this.native.setCb(bindWeak(this.cb, this, /* defaultReturn */ undefined));
}
cb(x: number) {
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment