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
53
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

alien-signals - npm Package Compare versions

Comparing version

to
0.6.0

benchs/complex.mjs

9

package.json
{
"name": "alien-signals",
"version": "0.5.0",
"version": "0.6.0",
"sideEffects": false,
"license": "MIT",
"description": "The fastest and lightest signal library.",
"description": "The lightest signal library.",
"packageManager": "pnpm@9.12.0",

@@ -40,3 +41,4 @@ "types": "./types/index.d.ts",

"test": "vitest run",
"bench": "npm run build:esm && node --jitless --expose-gc benchs/propagate.mjs"
"bench": "npm run build:esm && node --jitless --expose-gc benchs/propagate.mjs && node --jitless --expose-gc benchs/complex.mjs",
"bench:memory": "npm run build:esm && node --expose-gc benchs/memoryUsage.mjs"
},

@@ -47,5 +49,4 @@ "devDependencies": {

"typescript": "latest",
"vite": "latest",
"vitest": "latest"
}
}

@@ -9,10 +9,14 @@ <p align="center">

<h3 align="center">
<p>[<a href="https://github.com/YanqingXu/alien-signals-in-lua">Alien Signals in Lua</a>]</p>
<p>[<a href="https://github.com/medz/alien-signals-dart">Alien Signals in Dart</a>]</p>
<p>[<a href="https://github.com/Rajaniraiyn/react-alien-signals">React Binding</a>]</p>
</h3>
# alien-signals
Project Status: **Preview**
The goal of `alien-signals` is to create a ~~push-pull~~ [push-pull-push model](https://github.com/stackblitz/alien-signals/pull/19) based signal library with the lowest overhead.
The goal of `alien-signals` is to create a push-pull model based signal library with the lowest overhead.
We have set the following constraints in scheduling logic:
We have set the following scheduling logic constraints:
1. No dynamic object fields

@@ -83,2 +87,107 @@ 2. No use of Array/Set/Map

## 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`
```ts
export function propagate(link: Link, targetFlag: SubscriberFlags = SubscriberFlags.Dirty): void {
do {
const sub = link.sub;
const subFlags = sub.flags;
if (
(
!(subFlags & (SubscriberFlags.Tracking | SubscriberFlags.Recursed | SubscriberFlags.InnerEffectsPending | SubscriberFlags.ToCheckDirty | SubscriberFlags.Dirty))
&& (sub.flags = subFlags | targetFlag, true)
)
|| (
(subFlags & (SubscriberFlags.Tracking | SubscriberFlags.Recursed)) === SubscriberFlags.Recursed
&& (sub.flags = (subFlags & ~SubscriberFlags.Recursed) | targetFlag, true)
)
|| (
!(subFlags & (SubscriberFlags.InnerEffectsPending | SubscriberFlags.ToCheckDirty | SubscriberFlags.Dirty))
&& isValidLink(link, sub)
&& (
sub.flags = subFlags | SubscriberFlags.Recursed | targetFlag,
(sub as Dependency).subs !== undefined
)
)
) {
const subSubs = (sub as Dependency).subs;
if (subSubs !== undefined) {
propagate(
subSubs,
'notify' in sub
? SubscriberFlags.InnerEffectsPending
: SubscriberFlags.ToCheckDirty
);
} else if ('notify' in sub) {
if (queuedEffectsTail !== undefined) {
queuedEffectsTail.nextNotify = sub;
} else {
queuedEffects = sub;
}
queuedEffectsTail = sub;
}
} else if (
!(subFlags & (SubscriberFlags.Tracking | targetFlag))
|| (
!(subFlags & targetFlag)
&& (subFlags & (SubscriberFlags.InnerEffectsPending | SubscriberFlags.ToCheckDirty | SubscriberFlags.Dirty))
&& isValidLink(link, sub)
)
) {
sub.flags = subFlags | targetFlag;
}
link = link.nextSub!;
} while (link !== undefined);
if (targetFlag === SubscriberFlags.Dirty && !batchDepth) {
drainQueuedEffects();
}
}
```
#### `checkDirty`
```ts
export function checkDirty(link: Link): boolean {
do {
const dep = link.dep;
if ('update' in dep) {
const depFlags = dep.flags;
if (depFlags & SubscriberFlags.Dirty) {
if (dep.update()) {
const subs = dep.subs!;
if (subs.nextSub !== undefined) {
shallowPropagate(subs);
}
return true;
}
} else if (depFlags & SubscriberFlags.ToCheckDirty) {
if (checkDirty(dep.deps!)) {
if (dep.update()) {
const subs = dep.subs!;
if (subs.nextSub !== undefined) {
shallowPropagate(subs);
}
return true;
}
} else {
dep.flags = depFlags & ~SubscriberFlags.ToCheckDirty;
}
}
}
link = link.nextDep!;
} while (link !== undefined);
return false;
}
```
## Roadmap

@@ -85,0 +194,0 @@

@@ -1,2 +0,2 @@

import { IComputed, Link, SubscriberFlags } from './system.js';
import { IComputed, ILink, SubscriberFlags } from './system.js';
import type { ISignal } from './types.js';

@@ -6,9 +6,7 @@ export declare function computed<T>(getter: (cachedValue?: T) => T): Computed<T>;

getter: (cachedValue?: T) => T;
cachedValue: T | undefined;
version: number;
subs: Link | undefined;
subsTail: Link | undefined;
lastTrackedId: number;
deps: Link | undefined;
depsTail: Link | undefined;
currentValue: T | undefined;
subs: ILink | undefined;
subsTail: ILink | undefined;
deps: ILink | undefined;
depsTail: ILink | undefined;
flags: SubscriberFlags;

@@ -15,0 +13,0 @@ constructor(getter: (cachedValue?: T) => T);

@@ -1,15 +0,13 @@

import { Dependency, IEffect, Link, Subscriber, SubscriberFlags } from './system.js';
export declare let activeSub: Subscriber | undefined;
export declare let activeTrackId: number;
export declare let lastTrackId: number;
export declare function setActiveSub(sub: Subscriber | undefined, trackId: number): void;
export declare function nextTrackId(): number;
import { IDependency, IEffect, ILink, ISubscriber, SubscriberFlags } from './system.js';
export declare let activeSub: ISubscriber | undefined;
export declare function untrack<T>(fn: () => T): T;
export declare function setActiveSub(sub: ISubscriber | undefined): void;
export declare function effect<T>(fn: () => T): Effect<T>;
export declare class Effect<T = any> implements IEffect, Dependency {
export declare class Effect<T = any> implements IEffect, IDependency {
fn: () => T;
nextNotify: IEffect | undefined;
subs: Link | undefined;
subsTail: Link | undefined;
deps: Link | undefined;
depsTail: Link | undefined;
subs: ILink | undefined;
subsTail: ILink | undefined;
deps: ILink | undefined;
depsTail: ILink | undefined;
flags: SubscriberFlags;

@@ -16,0 +14,0 @@ constructor(fn: () => T);

@@ -1,7 +0,9 @@

import { Link, Subscriber, SubscriberFlags } from './system.js';
import { ILink, ISubscriber, SubscriberFlags } from './system.js';
export declare let activeEffectScope: EffectScope | undefined;
export declare function untrackScope<T>(fn: () => T): T;
export declare function setActiveScope(sub: EffectScope | undefined): void;
export declare function effectScope(): EffectScope;
export declare class EffectScope implements Subscriber {
deps: Link | undefined;
depsTail: Link | undefined;
export declare class EffectScope implements ISubscriber {
deps: ILink | undefined;
depsTail: ILink | undefined;
flags: SubscriberFlags;

@@ -8,0 +10,0 @@ notify(): void;

@@ -0,1 +1,2 @@

export * from './batch.js';
export * from './computed.js';

@@ -7,2 +8,2 @@ export * from './effect.js';

export * from './types.js';
export * as Unstable from './unstable/index.js';
export * from './unstable/index.js';

@@ -1,13 +0,12 @@

import { Dependency, Link } from './system.js';
import { IDependency, ILink } from './system.js';
import type { IWritableSignal } from './types.js';
export declare function signal<T>(): Signal<T | undefined>;
export declare function signal<T>(oldValue: T): Signal<T>;
export declare class Signal<T = any> implements Dependency, IWritableSignal<T> {
export declare class Signal<T = any> implements IDependency, IWritableSignal<T> {
currentValue: T;
subs: Link | undefined;
subsTail: Link | undefined;
lastTrackedId: number;
subs: ILink | undefined;
subsTail: ILink | undefined;
constructor(currentValue: T);
get(): NonNullable<T>;
get(): T;
set(value: T): void;
}

@@ -1,26 +0,23 @@

export interface IEffect extends Subscriber {
export interface IEffect extends ISubscriber {
nextNotify: IEffect | undefined;
notify(): void;
}
export interface IComputed extends Dependency, Subscriber {
version: number;
export interface IComputed extends IDependency, ISubscriber {
update(): boolean;
}
export interface Dependency {
subs: Link | undefined;
subsTail: Link | undefined;
lastTrackedId?: number;
export interface IDependency {
subs: ILink | undefined;
subsTail: ILink | undefined;
}
export interface Subscriber {
export interface ISubscriber {
flags: SubscriberFlags;
deps: Link | undefined;
depsTail: Link | undefined;
deps: ILink | undefined;
depsTail: ILink | undefined;
}
export interface Link {
dep: Dependency | IComputed | (Dependency & IEffect);
sub: Subscriber | IComputed | (Dependency & IEffect) | IEffect;
version: number;
prevSub: Link | undefined;
nextSub: Link | undefined;
nextDep: Link | undefined;
export interface ILink {
dep: IDependency | IComputed | (IDependency & IEffect);
sub: ISubscriber | IComputed | (IDependency & IEffect) | IEffect;
prevSub: ILink | undefined;
nextSub: ILink | undefined;
nextDep: ILink | undefined;
}

@@ -30,14 +27,16 @@ export declare const enum SubscriberFlags {

Tracking = 1,
CanPropagate = 2,
RunInnerEffects = 4,
Recursed = 2,
InnerEffectsPending = 4,
ToCheckDirty = 8,
Dirty = 16,
Dirtys = 24
Notified = 28
}
export declare function startBatch(): void;
export declare function endBatch(): void;
export declare function link(dep: Dependency, sub: Subscriber): Link;
export declare function propagate(subs: Link): void;
export declare function checkDirty(deps: Link, singleDep?: boolean): boolean;
export declare function startTrack(sub: Subscriber): void;
export declare function endTrack(sub: Subscriber): void;
export declare function drainQueuedEffects(): void;
export declare function link(dep: IDependency, sub: ISubscriber): void;
export declare function propagate(link: ILink): void;
export declare function shallowPropagate(link: ILink): void;
export declare function checkDirty(link: ILink): boolean;
export declare function startTrack(sub: ISubscriber): void;
export declare function endTrack(sub: ISubscriber): void;
export declare function isDirty(sub: ISubscriber, flags: SubscriberFlags): boolean;
export declare function runInnerEffects(link: ILink): void;
import { ISignal } from '../index.js';
export declare function computedArray<I, O>(arr: ISignal<I[]>, getGetter: (item: ISignal<I>, index: number) => () => O): readonly Readonly<O>[];
export declare function computedArray<I, O>(arr: ISignal<I[]>, getter: (item: I, index: number) => O): readonly Readonly<O>[];

@@ -1,3 +0,17 @@

export * from './computedArray.js';
export * from './computedSet.js';
export * from './equalityComputed.js';
import { AsyncComputed, asyncComputed } from './asyncComputed.js';
import { AsyncEffect, asyncEffect } from './asyncEffect.js';
import { asyncCheckDirty } from './asyncSystem.js';
import { computedArray } from './computedArray.js';
import { computedSet } from './computedSet.js';
import { EqualityComputed, equalityComputed } from './equalityComputed.js';
export declare const unstable: {
AsyncComputed: typeof AsyncComputed;
asyncComputed: typeof asyncComputed;
AsyncEffect: typeof AsyncEffect;
asyncEffect: typeof asyncEffect;
asyncCheckDirty: typeof asyncCheckDirty;
computedArray: typeof computedArray;
computedSet: typeof computedSet;
EqualityComputed: typeof EqualityComputed;
equalityComputed: typeof equalityComputed;
};

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet