fast reactive signals jsr.io/@mary/signals
typescript jsr
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor: only allow a single cleanup

Mary f5cbe894 911de469

+22 -45
+22 -45
mod.ts
··· 162 162 } 163 163 164 164 function cleanup_effect(effect: Effect<any>): void { 165 - const cleanups = effect._cleanups; 166 - if (cleanups.length > 0) { 165 + const cleanup = effect._cleanup; 166 + 167 + if (cleanup !== undefined) { 167 168 const prev_listener = eval_listener; 169 + 170 + effect._cleanup = undefined; 168 171 169 172 /*#__INLINE__*/ start_batch(); 170 173 eval_listener = undefined; 171 174 172 175 try { 173 - for (let i = 0, ilen = cleanups.length; i < ilen; i++) { 174 - (0, cleanups[i])(); 175 - } 176 + cleanup(); 176 177 } catch (err) { 177 178 // Failed to clean, so let's dispose of this effect. 178 179 effect._flags = (effect._flags & ~Flags.RUNNING) | Flags.DISPOSED; ··· 180 181 181 182 throw err; 182 183 } finally { 183 - cleanups.length = 0; 184 - 185 184 eval_listener = prev_listener; 186 185 187 186 end_batch(); ··· 490 489 } 491 490 } 492 491 493 - type CleanupFunction = () => void; 494 - 495 492 export class Effect<T = void> { 496 493 /** @internal Stored time of the write clock */ 497 494 _epoch = -1; ··· 502 499 /** @internal Context flags */ 503 500 _flags = Flags.TRACKING; 504 501 505 - /** @internal Registered cleanup functions */ 506 - _cleanups: CleanupFunction[] = []; 502 + /** @internal Registered cleanup function */ 503 + _cleanup?: () => void; 507 504 /** @internal Compute function for this effect */ 508 - _compute: (prev: T) => T; 505 + _compute: () => unknown; 509 506 /** @internal Stored value from this compute */ 510 507 _value!: T; 511 508 512 509 /** @internal Batched effects are queued by a linked list on itself */ 513 510 _next_batched_effect: Effect | undefined; 514 511 515 - constructor(compute: (prev: T) => T, initialValue: T) { 512 + constructor(compute: () => unknown) { 516 513 this._compute = compute; 517 - this._value = initialValue; 518 514 } 519 515 520 516 /** @internal */ ··· 528 524 const prev_listener = eval_listener; 529 525 const prev_sources = eval_untracked_sources; 530 526 const prev_sources_index = eval_sources_index; 527 + 528 + let ret: unknown; 531 529 532 530 cleanup_effect(this); 533 531 ··· 542 540 this._context_epoch = read_clock++; 543 541 this._flags = (flags & ~Flags.DIRTY & ~Flags.MAYBE_DIRTY) | Flags.RUNNING; 544 542 545 - this._value = (0, this._compute)(this._value); 543 + ret = this._compute(); 544 + 545 + if (typeof ret === 'function') { 546 + this._cleanup = ret as (() => unknown); 547 + } 546 548 } finally { 547 549 cleanup_context(); 548 550 ··· 611 613 } 612 614 613 615 /** 614 - * The effect function itself. 615 - */ 616 - export type EffectFunction<Prev, Next extends Prev = Prev> = (v: Prev) => Next; 617 - 618 - /** 619 616 * Run side-effects that get rerun when one of its signal dependencies change. 620 617 */ 621 - export function effect<Next extends Prev, Prev = Next>( 622 - fn: EffectFunction<undefined | NoInfer<Prev>, Next>, 623 - ): void; 624 - export function effect<Next extends Prev, Init = Next, Prev = Next>( 625 - fn: EffectFunction<Init | Prev, Next>, 626 - value: Init, 627 - ): void; 628 - export function effect<Next extends Prev, Init, Prev>( 629 - fn: EffectFunction<Init | Prev, Next>, 630 - value?: Init, 631 - ): void { 632 - // @ts-expect-error - messy overloads 633 - const instance = new Effect(fn, value); 618 + export function effect( 619 + fn: () => unknown, 620 + ): () => void { 621 + const instance = new Effect(fn); 634 622 635 623 try { 636 624 instance._refresh(); ··· 638 626 instance._dispose(); 639 627 throw err; 640 628 } 641 - } 642 629 643 - /** 644 - * Adds a cleanup function that gets run when an effect is rerun or destroyed 645 - * @param fn Cleanup function to run 646 - * @param throws Whether to throw if not under an effect, defaults to true 647 - */ 648 - export function cleanup(fn: () => void, throws = true) { 649 - if (eval_listener instanceof Effect) { 650 - eval_listener._cleanups.push(fn); 651 - } else if (throws) { 652 - throw new Error(`Cleanup function called outside of effect`); 653 - } 630 + return instance._dispose.bind(instance); 654 631 } 655 632 656 633 /**