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
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
- 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/sleep
helper) - Perfect for nested resource management or transactional consistency
npm install @your-scope/TreeLock
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
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)
Each TreeLock
instance exposes the following properties:
-
name
: The name of this lock. -
sup
: The parentTreeLock
instance (if any). -
subs
: Array of childTreeLock
instances. -
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.
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.
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.
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.
MIT