New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

alien-signals

Package Overview
Dependencies
Maintainers
1
Versions
46
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

alien-signals

The lightest signal library.

  • 1.1.0-alpha.2
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
785K
decreased by-9.7%
Maintainers
1
Weekly downloads
 
Created
Source


npm package

alien-signals

This project explores a push-pull based signal algorithm. Its current implementation is similar to or related to certain other frontend projects:

We impose some constraints (such as not using Array/Set/Map and disallowing function recursion) to ensure performance. We found that under these conditions, maintaining algorithmic simplicity offers more significant improvements than complex scheduling strategies.

Even though Vue 3.4 is already optimized, alien-signals is still noticeably faster. (I wrote code for both, and since they share similar algorithms, they’re quite comparable.)

Image

Benchmark repo: https://github.com/transitive-bullshit/js-reactivity-benchmark

Background

I spent considerable time optimizing Vue 3.4’s reactivity system, gaining experience along the way. Since Vue 3.5 switched to a pull-based algorithm similar to Preact, I decided to continue researching a push-pull based implementation in a separate project. Our end goal is to implement fully incremental AST parsing and virtual code generation in Vue language tools, based on alien-signals.

Derived Projects

Adoption

Usage

Basic APIs
import { signal, computed, effect } from 'alien-signals';

const count = signal(1);
const doubleCount = computed(() => count() * 2);

effect(() => {
  console.log(`Count is: ${count()}`);
}); // Console: Count is: 1

console.log(doubleCount()); // 2

count(2); // Console: Count is: 2

console.log(doubleCount()); // 4
Effect Scope
import { signal, effectScope } from 'alien-signals';

const count = signal(1);

const stopScope = effectScope(() => {
  effect(() => {
    console.log(`Count in scope: ${count()}`);
  }); // Console: Count in scope: 1

  count(2); // Console: Count in scope: 2
});

stopScope();

count(3); // No console output
Creating Your Own Public API

You can reuse alien-signals’ core algorithm via createReactiveSystem() to build your own signal API. For implementation examples, see:

About propagate and checkDirty functions

In order to eliminate recursive calls and improve performance, we record the last link node of the previous loop in propagate and checkDirty functions, and implement the rollback logic to return to this node.

This results in code that is difficult to understand, and you don't necessarily get the same performance improvements in other languages, so we record the original implementation without eliminating recursive calls here for reference.

propagate
function propagate(link: Link, targetFlag = SubscriberFlags.Dirty): void {
	do {
		const sub = link.sub;
		const subFlags = sub.flags;

		if (
			(
				!(subFlags & (SubscriberFlags.Tracking | SubscriberFlags.Recursed | SubscriberFlags.Propagated))
				&& (sub.flags = subFlags | targetFlag | SubscriberFlags.Notified, true)
			)
			|| (
				(subFlags & SubscriberFlags.Recursed)
				&& !(subFlags & SubscriberFlags.Tracking)
				&& (sub.flags = (subFlags & ~SubscriberFlags.Recursed) | targetFlag | SubscriberFlags.Notified, true)
			)
			|| (
				!(subFlags & SubscriberFlags.Propagated)
				&& isValidLink(link, sub)
				&& (
					sub.flags = subFlags | SubscriberFlags.Recursed | targetFlag | SubscriberFlags.Notified,
					(sub as Dependency).subs !== undefined
				)
			)
		) {
			const subSubs = (sub as Dependency).subs;
			if (subSubs !== undefined) {
				propagate(
					subSubs,
					subFlags & SubscriberFlags.Effect
						? SubscriberFlags.PendingEffect
						: SubscriberFlags.PendingComputed
				);
			} else if (subFlags & SubscriberFlags.Effect) {
				if (queuedEffectsTail !== undefined) {
					queuedEffectsTail.depsTail!.nextDep = sub.deps;
				} else {
					queuedEffects = sub;
				}
				queuedEffectsTail = sub;
			}
		} else if (!(subFlags & (SubscriberFlags.Tracking | targetFlag))) {
			sub.flags = subFlags | targetFlag | SubscriberFlags.Notified;
			if ((subFlags & (SubscriberFlags.Effect | SubscriberFlags.Notified)) === SubscriberFlags.Effect) {
				if (queuedEffectsTail !== undefined) {
					queuedEffectsTail.depsTail!.nextDep = sub.deps;
				} else {
					queuedEffects = sub;
				}
				queuedEffectsTail = sub;
			}
		} else if (
			!(subFlags & targetFlag)
			&& (subFlags & SubscriberFlags.Propagated)
			&& isValidLink(link, sub)
		) {
			sub.flags = subFlags | targetFlag;
		}

		link = link.nextSub!;
	} while (link !== undefined);
}
checkDirty
function checkDirty(link: Link): boolean {
	do {
		const dep = link.dep;
		if ('flags' in dep) {
			const depFlags = dep.flags;
			if ((depFlags & (SubscriberFlags.Computed | SubscriberFlags.Dirty)) === (SubscriberFlags.Computed | SubscriberFlags.Dirty)) {
				if (updateComputed(dep)) {
					const subs = dep.subs!;
					if (subs.nextSub !== undefined) {
						shallowPropagate(subs);
					}
					return true;
				}
			} else if ((depFlags & (SubscriberFlags.Computed | SubscriberFlags.PendingComputed)) === (SubscriberFlags.Computed | SubscriberFlags.PendingComputed)) {
				if (checkDirty(dep.deps!)) {
					if (updateComputed(dep)) {
						const subs = dep.subs!;
						if (subs.nextSub !== undefined) {
							shallowPropagate(subs);
						}
						return true;
					}
				} else {
					dep.flags = depFlags & ~SubscriberFlags.PendingComputed;
				}
			}
		}
		link = link.nextDep!;
	} while (link !== undefined);

	return false;
}

FAQs

Package last updated on 20 Jan 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc