Morphos & Kosmesis are here.Explore
PraxisJS

@praxisjs/concurrent

Changelog for @praxisjs/concurrent — @Task, @Queue, and @Pool for async concurrency control.

@praxisjs/concurrent

1.3.10

Depends on the other @praxisjs/* packages through caret ranges (^2.3.0) instead of exact versions, so npm no longer installs a second copy of a package when two releases disagree, and upgrades no longer end in peer conflicts.

1.3.9

The published package no longer contains the package's tests (compiled tests in dist/__tests__, test sources in src/__tests__).

The package is marked "sideEffects": false, so bundlers leave out the modules of it that an app does not use.

@Task, @Queue and @Pool throw a TypeError when the class is defined if they decorate an accessor instead of a plain field, naming the member to fix (see assertFieldContext).

Faster decorated components and calls. Measured in Node:

  • Whether a method takes an AbortSignal is now detected once per method instead of reading its source with fn.toString() for every new instance. With the field value returned from the decorator's initializer, constructing a component with @Task, @Queue and @Pool is about 2.5x faster.
  • loading, error, pending, active and lastResult read their signals directly instead of through a wrapping computed(), and state that changes together is published in one batch, so an effect reading loading and lastResult runs once per change.
  • An AbortController is only created when the method takes a signal. The synchronous part of a @Task call is about 13x cheaper.
  • @Queue and @Pool take items from the front of their backlog in constant time. Draining 20 000 queued calls went from about 156 ms to 6 ms.

Fix: @Pool read its own active signal while scheduling, so calling a pool from inside an effect subscribed that effect to the pool's state and ran it again each time a task started or finished.

1.3.0

Opt-in AbortSignal support for @Task, @Queue, and @Pool.

Name the first parameter of your async method signal to receive a live AbortSignal. The decorator detects the parameter name and injects it automatically — callers are unaffected and methods without a signal parameter continue to work exactly as before.

async loadUser(signal: AbortSignal, id: number) {
  return fetch(`/api/users/${id}`, { signal }).then(r => r.json())
}

What changed per primitive:

  • @Task — each new invocation aborts the previous call's signal; cancelAll() also aborts the active signal.
  • @Queue — clear() now also aborts the currently running call's signal in addition to cancelling pending items.
  • @Pool — new cancelAll() method; aborts all active signals and resolves all pending calls as undefined.

AbortError is never stored in .error() — it is treated as intentional cancellation.

QueueClearedError is now exported from the package root: import { QueueClearedError } from '@praxisjs/concurrent'.

1.2.9

Updated dependencies — @praxisjs/[email protected], @praxisjs/[email protected].

1.2.8

Updated dependencies — @praxisjs/[email protected].

1.2.7

Updated dependencies — @praxisjs/[email protected].

1.2.6

Updated dependencies — @praxisjs/[email protected], @praxisjs/[email protected].

1.2.5

Updated dependencies — @praxisjs/[email protected], @praxisjs/[email protected].

1.2.4

Updated dependencies — @praxisjs/[email protected], @praxisjs/[email protected].

1.2.3

Updated dependencies — @praxisjs/[email protected], @praxisjs/[email protected].

1.2.2

Refreshed workspace dependencies for stability and security. Updated dependencies — @praxisjs/[email protected].

1.2.1

Updated dependencies — @praxisjs/[email protected], @praxisjs/[email protected].

1.2.0

@Task, @Queue, @Pool redesigned as field decorators.

Each decorator now goes on a separate field next to the async method, not on the method itself. The method name is the first argument. Reactive state is accessed as sub-properties with full TypeScript intellisense via TaskOf, QueueOf, PoolOf:

// before
@Task()
async loadUser(id: number) { ... }
// this.loadUser_loading() — no intellisense

// after
async loadUser(id: number) { ... }

@Task('loadUser')
taskLoadUser!: TaskOf<MyClass, 'loadUser'>
// this.taskLoadUser(1)         ✓ — call it
// this.taskLoadUser.loading()  ✓ — reactive boolean
// this.taskLoadUser.error()    ✓ — reactive Error | null

@Pool argument order changed

@Pool now takes the method name first, concurrency second: @Pool('method', 3) (was @Pool(3, 'method')).

1.0.0

Breaking — functional APIs removed

RemovedReplacement
task(method)@Task('method') field decorator
queue(method)@Queue('method') field decorator
pool(n, method)@Pool('method', n) field decorator

0.1.0

Initial beta release.

On this page