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

particl

v0.8.3

Published

A small, easy to use JavaScript module that provides asynchronous control flow, event/property listeners, barriers, and more.

Downloads

519

Readme

particl

A small, easy to use JavaScript module that provides asynchronous control flow, event/property listeners, barriers, and more.

particl is the spiritual successor to atom, using some more modern language features and adding Promise support and more thorough tests.

Features

  • Small, depending only on core-js for older browser support.
  • Allows you to clearly code using a variety of async control flow patterns, even ones that would be cumbersome to implement clearly with just Promises.

Install

  npm install particl

Tutorial

Constructor

You can call the particl() constructor without arguments, but it's also possible to pass in initial properties as an object, and/or a callback function which will be immediately invoked.

  // no arguments
  let p = particl();

  // initial values
  p = particl({ prop1: 'value1', prop2: 'value2' });

  // exploded api view
  p = particl(({ get, set, need, provide, ... }) => {
    ...
  });
  p = particl({ prop1: 'value1' }, ({ get, set, need, provide, ... }) => {
    ...
  });

The exploded api form simply makes the entire instance API available as the first argument to the callback, so that you can easily select the portion of the api you want to interact with using argument destructuring.

So the following are identical:

  const p = particl();
  p.set('foo', 'bar');

  const p = particl({ foo: 'bar' });

  const p = particl(({ set }) => {
    set({ foo: 'bar' });
  });

Properties

A particl has properties. The get() and set() methods may be employed to read and write values of any type:

  particl(({ get, set }) => {

    set('key', 'value');
    console.log('Value of key:', get('key'));

    set({
      pi: 3.141592653,
      r: 5,
      circumference: () => 2 * get('pi') * get('r'),
    });
    console.log('Circumference:', get('circumference')());
  });

If an object is passed in to the constructor, it will initialize properties:

  p = particl({ p: 3.141592653, r: 5 });

Use has() to query for existence of a property, and keys() to get a list of all properties that have been set.

  if (p.has('skills')) {
    console.log('What "p" brings to the table:', p.keys());
  }

The each() method lets you execute a function on a series of properties.

  p.set({ r: 0xBA, g: 0xDA, b: 0x55 });
  p.each(['r', 'g', 'b'], (key, value) => {
    console.log(`${key}:${value}`);
  });

Listeners

Listeners may be attached to particls in a variety of ways.

To be notified as soon as a property is set, use the once() method. The callback will be called immediately if the property is already set.

  p.once('user', (user) => {
    alert(`Welcome, ${user.name}!`);
  });

or

  p.once('user').then((user) => {
    alert(`Welcome, ${user.name}!`);
  });

Many particl methods can work with more than one property at a time.

  p.once(['app', 'user'], (app, user) => {
    alert(`Welcome to ${app.name}, ${user.name}!`);
  });

or

  p.once(['app', 'user']).then(({ app, user }) => {
    alert(`Welcome to ${app.name}, ${user.name}!`);
  });

When you just want to know about the next change, even if the property is already set, use next().

  p.next('click', (click) => {
    alert(`Are you done clicking on ${click.button} yet?`);
  });

To watch for any future changes to a property, use the on() method.

  function myErrorHandler(error) {
    console.log(`There was a grievous calamity of code in ${p.get('module')}`);
    console.log(error);
  }
  p.on('error', myErrorHandler);

Note that setting a property with a primitive (string/number/boolean) value will only trigger listeners if the value is different. On the other hand, setting an array or object value will always trigger listeners.

You can unregister any listener using off().

  p.off(myErrorHandler);

Needs and Providers

You can register a provider for a property.

  particl(({ need, on, provide }) => {
    provide('privacyPolicy', () => fetch(`${baseUrl}/privacy.txt`));

    on('clickPrivacy', async () => {
      element.innerText = await need('privacyPolicy');
    });
  });

Providers only get invoked if there is a need, and if the property is not already set. Use the need() method to declare a need for a particular property. If a corresponding provider is registered, it will be invoked. Otherwise, need() behaves just like once().

Exploded view

If you call explode(func) or else just pass in a function to the constructor, it will be called with the entire api object, allowing you to easily select just individual methods you want with argument destructuring:

  particl(async ({ get, need, on, provide, set }) => {
    set({ logDefaults: { appName: 'myApp' }});

    on('log', (event) => {
      console.log({
        ...get('logDefaults'),
        ...event,
        timestamp: Date.now(),
      });
    });
    const log = event => set('log', event);

    provide('data', () => fetch('${baseUrl}/api/data'));

    const data = await need('data');
    log({ msg: 'data loaded '});

    ...
  });

Extending functionality with mixins

The particl constructor provides a way to incorporate mixins that extend the particl's api. Use it like this:

  particl(
    [ ...mixins ],
    ({ on, set, get, need, customMethodFromMixin, ... }) => {

    }
  );

Some helpful mixins are included in the mixins/ directory. Fox example, use the customListeners mixin to create customized method names for specific properties:

  const customListenersMixin = require('particl/dist/mixins/customListeners');

  particl(
    [customListenersMixin('event')],
    ({ onEvent, onceEvent, setEvent }) => {
      // This is a convenient shorthand for on('event', (evt) => { ... })
      onEvent((evt) => {
        console.log('Something happened:', evt);
      });
    }
  );

Or use the matchers mixin to add validation to your property listeners:

  const matchersMixin = require('particl/dist/mixins/matchers');

  particl(
    [matchersMixin],
    async ({ onceMatch, set }) => {
      set('authStatus', { authenticated: false });

      ...

      const isAuthenticated = (authStatus) => (authStatus?.authenticated);
      await onceMatch('authStatus', isAuthenticated);
      // We only get here once the user is authenticated
    }
  );