npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

synchronization-atom

v2.0.2

Published

A powerful (& typed) zero-dependency primitive to help build other synchronization primitives like locks, semaphores, events, or barriers

Downloads

174

Readme

npm NPM GitHub issues npm bundle size npm GitHub forks GitHub Repo stars

synchronization-atom

A powerful (& typed) zero-dependency primitive to help build other synchronization primitives including but not limited to: locks, semaphores, events, barriers, channels

This project was heavily inspired by mobx's when

Installation

# pnpm
pnpm add --save synchronization-atom

API

atom

function atom<T>(initialState: T): Atom<T>

Creates and returns an Atom<T> with the given initialState: T.

async atom.conditionallyUpdate

interface Atom<T> {
    ...
    conditionallyUpdate: (
        predicate: (state: T) => boolean,
        nextState: T | ((state: T) => T),
        sideEffect?: (state: T) => void,
        abortSignal?: AbortSignal
    ) => Promise<T>
    ...
}
  • Updates the atom's state to nextState if the current state satisfies the predicate.
  • If the current state does not satisfy the predicate, the call blocks until the predicate is satisfied.
  • If a sideEffect is provided, it is executed atomically as part of the update (i.e. no other update or side-effect will be running simultaneously against the atom).
  • Can be cancelled via an optional AbortSignal as last argument.

async atom.waitFor

interface Atom<T> {
    ...
    waitFor: (
        predicate: (state: T) => boolean,
        reaction?: (state: T) => void,
        abortSignal?: AbortSignal
    ) => Promise<T> | void
    ...
}
  • Blocks until the atom's state satisfies the predicate, unless a reaction is provided.
  • If a reaction is provided, the call returns immediately, and when the predicate is satisfied, the reaction is executed.
  • Can be cancelled via an optional AbortSignal as last argument.

atom.getState

interface Atom<T> {
    ...
    getState: () => T
    ...
}

Returns the current state of the atom.

Usage Examples

Make a lock

import {atom} from 'synchronization-atom';

const lockAtom = atom(false /* is locked */);

async function test(n: number) {
    // aquire lock
    await lockAtom.conditionallyUpdate(
        (locked) => locked === false,
        true
    );

    console.log(n, `aquired lock`);
    await doCrazyAsyncStuffHere();
    console.log(n, `releasing lock`);

    // release lock
    lockAtom.conditionallyUpdate(() => true, false);
}

Promise.all([test(1), test(2), test(3)]);

Make a semaphore

import { atom } from 'synchronization-atom';

const semaphoreAtom = atom(3 /* no. of seats */);

async function test(n: number) {
    // aquire lock
    await semaphoreAtom.conditionallyUpdate(
        (seats) => seats > 0,
        (seats) => seats - 1
    );
    
    console.log(n, `aquired lock`);
    await doCrazyAsyncStuffHere();
    console.log(n, `releasing lock`);
    
    // release lock
    semaphoreAtom.conditionallyUpdate(
        () => true,
        seats => seats + 1
    );
}

Promise.all([test(1), test(2), test(3), test(4), test(5)]);

Make a event

import { atom } from 'synchronization-atom';

const eventAtom = atom(false /* is event set */);

async function test(n: number) {
    console.log(n, `waiting for event`);
    await eventAtom.waitFor((isSet) => isSet === true);

    console.log(n, `running`);
}

Promise.all([test(1), test(2), test(3)]);

console.log(`setting event`);
eventAtom.conditionallyUpdate(() => true, true);

Make a barrier

import { atom } from 'synchronization-atom';

const barrierAtom = atom(3 /* empty seats */);

async function test(n: number) {
    await barrierAtom.conditionallyUpdate(
        () => true,
        (emptySeats) => emptySeats - 1
    );

    console.log(n, `waiting for seats to fill`);
    await barrierAtom.waitFor((emptySeats) => emptySeats < 0);

    console.log(n, `running`);
}

Promise.all([test(1), test(2), test(3), test(4), test(5)]);

Why?

I often use async calls like separate threads or at least like Go routines, as in as long as I'm fetching from DB or API over a network, it is effectively multi-threading (at least in my head).

Sadly I couldn't enjoy the very powerful sync primitives that Python, Java or Go has to offer.

Simultaneously, I noticed different standard libraries of the different languages have a different set of sync primitives but mutexes were at the heart.

I set out to create these primitives for JS while basing them off of a single primitive that is analogous to a mutex, but on parr with the level of expressiveness and ease we come to expect from the JS ecosystem.

synchronization-atom is the result of that effort.

Omran Jamal

License

MIT