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 🙏

© 2025 – Pkg Stats / Ryan Hefner

sg.js

v0.1.0

Published

SG

Readme

SG

Utility to handle side effects with generators. Inspired by redux-saga and co.

An effect is an object that describe a task, but do not execute it. This allows to separate the tasks scheduling from the tasks themself.

install

npm install

Introduction

The sg function takes a generator yielding effect and returns a function which return a promise.

import { call } from 'sg/effects';
function* gen(name) {
    //...
    yield call(console.log, `hello ${name}`);

    return 'done';
}

const func = sg(gen);

func('world')
.then((result) => {
    console.log(result); // done
});

effects

The effects are helper functions which return an object describing what to do.

const effect = call(console.log, 'hello world');
// effect:
{
    type: 'call',
    handler: // function that will execute the effect: called with arg, and returning a promise
    args: [console.log, 'hello world'], // args passed to the effect function
}

call

Calls a function (normal, async or returning a promise) or a generator yielding effect and either returns the value or throws an error.

const add = (a, b) => a + b;
const addPromise = (a, b) => new Promise((resolve, reject) => {
    try {
        resolve(a + b);
    } catch (error) {
        reject(error);
    }
})
const addAsync = async (a, b) => await Promise.resolve(a + b);
function* addGenerator(a, b) {
    const c = yield call(add, a, b);
    const d = yield call(addPromise, a, c);
    return yield call(addAsync, b, d);
}

thunk

Calls a thunk function and either returns the value or throws an error. A thunk function is a function that returns an asynchronous function taking a callback.

const add = (a, b) => cb => cb(null, a + b);

co

Calls a co style generator (yielding promise or thunk, not effect).

function* add(a, b) {
    return yield Promise.resolve(a + b);
}

cps

Calls a continuation passing style function.

const add = (a, b, cb) => cb(null, a + b);

put

emit an event

yield put('my event', { payload: data });

take

Waits for event sent by put and return its payload

const payload = yield take('my event'); // { payload: data }

spawn

Launches another sg generator, but do not wait for it to end, returning a task object.

const task = yield spawn(sgGenerator);

fork

Same as spawn, but errors from the forked generator will bubble up to the parent generator making it fail. Also the parent generator will wait for the forked generator to end before resolving.

const task = yield fork(sgGenerator);

cancel

takes a task returned by fork or spawn, and cancels it, ending it and its children.

yield cancel(task);

join

takes a task returned by fork or spawn, and joins it, waiting for the task to end or throw an error.

const result = yield join(task);

race

yields several effect simultaneously in a literal and returns only the result of the first completed effect, or its error if it failed.

const { user, cancel } = yield race({
    user: yield call(fetchUser),
    cancel: yield take('CANCEL'),
});

takeEvery

forks given generator each time given event is triggered. It is the same as forking the following generator:

function* takeEverySaga(type, gen, ...args) {
    while (true) {
        const action = yield take(type);
        yield fork(gen, ...args.concat(action));
    }
}

task

Object returned by fork and spawn. It has a done and cancel method.

  • done: returns a promise, which resolves with task result or rejects with task error.
  • cancel: Cancels the task if it is still running. This in turn will also cancel all children of this task.

Adding your own custom effects with createEffect

You can create your own effect with createEffect. It takes a type, and an handler.

  • Type: A string with the effect name
  • Handler: a function returning a promise and that receives three arguments:
    • effect parameters: an array with the list of argument passed to the effect function
    • emitter An event emitter used internally for the take and put effects.
    • id The internal id of the current saga. You will probably never need this.

Example of custom effect:

import sg, { createEffect } from 'sg.js';
import { createEffect } from 'sg.js/effects';

function handleSql([sql, parameter]) {
    return executeQueryAndReturnAPromise(sql, parameter);
}

const sqlEffect = createEffect('sql', handleSql);

sqlEffect('query', 'parameter'); give

{
    type: 'sql',
    handle: handleSql,
    args: ['query', 'parameter'],
}

Our sqlEffect can be used in a generator like this.

sg(function* (userData) {
    yield sqlEffect('INSERT ... INTO user', userData);
})({ name: 'john' });

During execution handleSql will get called like so

handleSql(['INSERT ... INTO user', userData]);

Injecting Custom EventEmitter

Sg use an eventEmitter internally to handle take and put effects. It is possible to pass your own eventEmitter to sg. This allows to take events from this event emitter. Your event emitter must extends node event emitter.