Skip to content

v2.0.0

Latest
Compare
Choose a tag to compare
@johnsoncodehk johnsoncodehk released this 30 Apr 12:54
· 38 commits to master since this release

Version 2.0 rethinks and optimizes the reactive system model, with minimal impact on users who only use the surface APIs. If you extend or deeply utilize alien-signals, please pay attention to the "Reactive Model Refactor" section.

Changes to Surface APIs

  • Added four new APIs: getCurrentSub, setCurrentSub, getCurrentScope, setCurrentScope

Deferred Signal Value Evaluation

Differences from v1

In v1, assigning a value to a signal immediately propagated the Dirty flag, causing some computed values to be unnecessarily re-evaluated.

// v1
const src = signal(10);
const double = computed(() => src() * 2);

double(); // -> 20

src(999); // double.flags -> Dirty
src(10);  // no effect

double(); // -> 20 (recomputed unnecessarily)

In v2, assigning a value to a signal only propagates the Pending flag, reducing unnecessary recomputation. Actual evaluation occurs during the next read.

// v2
const src = signal(10);
const double = computed(() => src() * 2);

double(); // -> 20

src(999); // src.flags -> Dirty, double.flags -> Pending
src(10);  // no effect

double(); // Checks src state -> unchanged, no recomputation needed

Effect Scope Parent-Child Hierarchy

In v2, recursive cleanup is achieved through a parent-child structure:

const scope1 = effectScope(() => {
	const scope2 = effectScope(() => {
		effect(() => ...);
		computed(() => ...);
	});
});

scope1();

Calling scope1() automatically cleans up its child scope scope2.

To make scope2 independent of scope1, temporarily set activeScope = undefined manually:

const scope1 = effectScope(() => {
	const prev = setCurrentScope(undefined);
	const scope2 = effectScope(() => {
		effect(() => ...);
		computed(() => ...);
	});
	setCurrentScope(prev);
});

Reactive Model Refactor

  • Merged Subscriber and Dependency into ReactiveNode
  • Trigger unwatched(dep) when all subscribers are lost, without recursively clearing subsequent subscribers
  • propagate now only propagates Pending; to immediately mark Dirty, call propagate + shallowPropagate after assignment
  • Adjusted naming for EffectFlags and ReactiveFlags; removed unused flags

Updated Options and APIs

  • notifyEffect β†’ notify
  • updateComputed β†’ update
  • Added the unwatched option for custom handling when all subscribers are lost
  • Removed processEffectNotifications, processComputedUpdate, processPendingInnerEffects, updateDirtyFlag
  • Added unlink, checkDirty

For performance differences, please refer to js-reactivity-benchmark.

Contributors

Thanks~

Special Sponsor

Next Generation Tooling

Platinum Sponsors

An approachable, performant and versatile framework for building web user interfaces.

Stay in the flow with instant dev experiences.
No more hours stashing/pulling/installing locally

β€” just click, and start coding.

Essential tools for software developers and teams.

Silver Sponsors

You?