@randajan/treelock
v0.3.1
Published
A minimal async lock with timeout support and parent-child queueing.
Maintainers
Readme
@randajan/treelock
TreeLock is a minimalist and deterministic locking mechanism for JavaScript that organizes asynchronous operations into a hierarchical, tree-like structure. Each lock node cooperates with its root and its branches to ensure that tasks are executed in the correct order — peacefully, predictably, and without deadlocks.
“I shall wait until I am calm, my root is calm, and all my branches are calm.”
— TreeLock, probably
Why TreeLock?
Because sometimes, simple promises and semaphores aren't enough. You need:
- 🧠 Smart queueing based on hierarchy
- 🌿 Elegant dependency propagation
- 🔒 Synchronized task execution across nested contexts
- ☯️ Inner peace in your asynchronous flows
Features
- Deterministic task order based on time of registration
- Propagated locking from root to branches
- Automatically delays conflicting operations
- Lightweight and dependency-free (except for a
@randajan/sleephelper) - Perfect for nested resource management or transactional consistency
Installation
npm install @your-scope/TreeLockUsage
import { TreeLock } from "@your-scope/TreeLock";
const root = new TreeLock();
const A = root.sub();
const B = root.sub();
await Promise.all([
root.run(() => sleep(100)),
A.run(() => sleep(100)),
B.run(() => sleep(100))
]);This guarantees that:
- Tasks run in order of registration
- No two conflicting branches will run simultaneously
- Root tasks block all branches, but branches can run in parallel if root is free
Options
You can pass the following options to the TreeLock constructor or the .sub() method:
name(string, optional): Just a label, useful for logging/debugging.ttl(number, optional): Timeout in milliseconds for each task. Tasks exceeding this limit are cancelled.on(function(lock, status, result), optional): A callback for each lock event:enter,start,done,timeout,error.sup(TreeLock, optional): Used to attach a children to a parent (sub to sup)
Properties
Each TreeLock instance exposes the following properties:
name: The name of this lock.sup: The parentTreeLockinstance (if any).subs: Array of childTreeLockinstances.ram: Number of currently running tasks in this lock.ramSup: Number of currently running tasks in all parent locks.ramSub: Number of currently running tasks in all child locks.queue: A Promise that resolves once all currently enqueued tasks are done.
API
run(fn, ttl?, ...args): Promise<void>
Runs a task within the lock. Waits for its turn based on the lock tree structure.
fn: Function to execute.ttl: Optional timeout in milliseconds....args: Arguments to pass tofn.
Returns a promise that resolves when the task finishes or rejects on timeout/error.
wrap(fn, ttl?): (...args) => Promise<void>
Wraps a function with the lock logic. Useful for passing locked functions around.
fn: Function to wrap.ttl: Optional timeout in milliseconds.
Returns a new function that automatically runs inside the lock.
sub(options?): TreeLock
Creates a child TreeLock bound to this one.
Main benefits:
- Any task scheduled on this child will wait for all parent locks to be free.
- Any task scheduled at parent will also lock it's subtree
options: Same options as constructor (exceptsup, which is inherited).
Returns a new TreeLock instance.
License
MIT
