Last active
November 30, 2022 22:29
-
-
Save brecert/14fd9e33e0f2d71b11b229be9fcabca0 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Utils | |
type Fn<T = void> = () => T | |
type None = typeof None | |
const None = Symbol() | |
const $batched: Set<Fn> = new Set() | |
// The behavior for batches will be different from wires | |
// unsure why but it feels right | |
let $inBatch = 0 | |
export function batch(fn: Fn) { | |
$inBatch++ | |
fn() | |
if ($inBatch <= 1) { | |
const fns = [...$batched.values()] | |
$batched.clear() | |
fns.map(fn => fn()) | |
} | |
$inBatch-- | |
} | |
const callBatched = (fn: Fn) => $inBatch > 0 | |
? $batched.add(fn) | |
: fn() | |
// Signals | |
const Signal = Symbol() | |
export type Signal<T> = { | |
readonly [Signal]: symbol | |
get value(): T | |
set value(value: T) | |
} | |
const $signals: Record<symbol, Set<Fn>> = {} | |
export function signal<T>(val: T) { | |
const id = Symbol(); | |
const on = ($signals[id] = new Set) | |
return { | |
[Signal]: id, | |
get value() { | |
return val | |
}, | |
set value(value: T) { | |
val = value | |
on.forEach(callBatched) | |
}, | |
dispose() { | |
$signals[id].clear() | |
} | |
} | |
} | |
export function compute<R, T>(fn: Fn<R>, signals: Signal<T>[]) { | |
let result = signal<R>(None as R); | |
let run = () => batch(() => (result.value = fn())) | |
let update = on(signals, run) | |
return { | |
[Signal]: result[Signal], | |
get value() { | |
return result.value === None | |
? (result.value = fn()) | |
: result.value | |
}, | |
dispose() { | |
update.unsubscribe() | |
result.dispose() | |
} | |
} | |
} | |
export function on<R, T>(signals: Signal<T>[], fn: Fn<R>) { | |
signals.forEach(signal => $signals[signal[Signal]].add(fn)) | |
return { | |
unsubscribe() { | |
signals.forEach(signal => $signals[signal[Signal]].delete(fn)) | |
} | |
} | |
} | |
const a = signal(1) | |
const b = signal(1) | |
const dbl = compute(() => a.value + b.value, [ a, b ]) | |
on([ dbl ], () => { | |
console.log('on', dbl.value, a.value, b.value) | |
}) | |
batch(() => { | |
a.value = 2 | |
b.value = 4 | |
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Utils | |
type Fn<T = void> = () => T | |
type None = typeof None | |
const None = Symbol() | |
const $batched: Set<Fn> = new Set() | |
// The behavior for batches will be different from wires | |
// unsure why but it feels right | |
let $inBatch = 0 | |
export function batch(fn: Fn) { | |
$inBatch++ | |
fn() | |
if ($inBatch <= 1) { | |
const fns = [...$batched.values()] | |
$batched.clear() | |
fns.map(fn => fn()) | |
} | |
$inBatch-- | |
} | |
const callBatched = (fn: Fn) => $inBatch > 0 | |
? $batched.add(fn) | |
: fn() | |
// Signals | |
const Signal = Symbol() | |
export type Signal<T> = { | |
readonly [Signal]: symbol | |
get value(): T | |
set value(value: T) | |
} | |
const $signals: Record<symbol, Set<Fn>> = {} | |
export function signal<T>(val: T) { | |
const id = Symbol(); | |
const on = ($signals[id] = new Set) | |
return { | |
[Signal]: id, | |
get value() { | |
return val | |
}, | |
set value(value: T) { | |
val = value | |
on.forEach(callBatched) | |
}, | |
dispose() { | |
$signals[id].clear() | |
} | |
} | |
} | |
export function compute<R, T>(fn: Fn<R>, signals: Signal<T>[]) { | |
let result = signal<R>(None as R); | |
let run = () => batch(() => (result.value = fn())) | |
let update = on(signals, run) | |
return { | |
[Signal]: result[Signal], | |
get value() { | |
return result.value === None | |
? (result.value = fn()) | |
: result.value | |
}, | |
dispose() { | |
update.unsubscribe() | |
result.dispose() | |
} | |
} | |
} | |
export function on<R, T>(signals: Signal<T>[], fn: Fn<R>) { | |
signals.forEach(signal => $signals[signal[Signal]].add(fn)) | |
return { | |
unsubscribe() { | |
signals.forEach(signal => $signals[signal[Signal]].delete(fn)) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment