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

@frptools/propagate

v1.0.0

Published

[FRPTools] Propagate is a fast, minimal signalling library

Downloads

4

Readme

FRPTools: Propagate

A fast, lightweight signalling library with a minimal, foolproof API

NPM version GitHub version Gitter

npm install @frptools/propagate

Define source values:

import { signal } from '@frptools/propagate';

const left = signal(7);
const right = signal(9);

Define a computed value by supplying a compute function, followed by a signal for each parameter of the compute function:

const sum = signal((a, b) => a + b, left, right);

Consume the value of any signal by observing it:

// The following will immediately log "Value: 16" to the console
const observer = sum.subscribe(value => console.log('Value:', value));

// The signal's value can also be sampled (as long as at least one dependent observer is active)
const currentValue = sum.value;

// Disconnect the observer when it is no longer needed (no further cleanup required)
observer.disconnect();

// A disconnected observer can be retained and reconnected later if desired
observer.reconnect();

Change source values to instantly recompute any derivative signal values:

// The following will trigger the above observer, logging "Value: 19" to the console
left.value = 10;

If ad-hoc sampling is required and no callback is required, the callback function can be omitted during observation:

const source = signal();
const downstream = performSomeCalculations(source);

const observer = downstream.observe();

setInterval(() => source.value = measureSomeExternalValue(), 50); // update the source every 50ms

setTimeout(() => {
  console.log(downstream.value); // sample the value after 1337ms
  observer.disconnect(); // ... then disconnect
}, 1337);

The library's implementation avoids the "combine problem", which is an issue in reactive programming where changes made to upstream signals cascade and converge independently in downstream signal inputs, causing multiple redundant recomputations as each of a signal's respective inputs receive new values during the same batch operation.

Without having handled this problem, the following example would propagate no less than six recomputation events to the observer for a single change to the a signal's value, as each signal's value propagates through the signal graph.

Instead, all redundant computations are avoided until all of a signal's inputs have been resolved, and the observer in the example receives only the final result of the cascade of changes occurring within the upstream graph.

import { signal } from '@frptools/propagate'

const add = (a, b) => a + b;
const subtract = (a, b) => a - b;
const multiply = (a, b) => a * b;
const negative = (a) => -a;

const a = signal(2);
const b = signal(4);
const c = signal(add, a, b);
const d = signal(subtract, b, a);
const e = signal(Math.pow, c, a);
const f = signal(negative, e);
const g = signal(multiply, e, d);
const h = signal(add, f, g);

const show = x => console.log(`the value is now: ${x}`);
h.observe(show); // --> the value is now: 36

a.value = 3; // --> the value is now: 0
b.value = 5; // --> the value is now: 512

When you need to change several source values as a batch operation before recomputation should occur, use a Cascade instance to defer recomputation until manually triggered. The Cascade class is used internally for the same reasons described above.

Use a source's set method, passing a new value and a reference to the Cascade object, followed by a call to the update method to complete the operation when all necessary source updates have been made:

import { signal, Cascade } from '@frptools/propagate';

// ... (assuming the previous example code is here)

const batch = new Cascade();

a.set(2, batch); // no recomputation occurs yet
b.set(4, batch); // still no recomputation...

// Call the `update` method to trigger recomputation in the graph:
batch.update(); // --> the value is now: 36