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

setlist

v0.2.3

Published

Sequential-ish your asynchronous code with ES6 Generator Function and Promise

Downloads

36

Readme

SetlistJS

Build Status Coverage Status Known Vulnerabilities

Setlist will sequential-ish your asynchronous code with ES6 Generator Function and Promise - Say goodbye to indentation hell.

TOC

Setup

Install it with npm.

npm install --save setlist

Then use them in your project by requiring setlist.

const run = require('setlist');

Getting Started

This topics requires you to understand the basics of Promise https://www.promisejs.org

This is an example of function using Promises to handle some asynchronous operation.

// Suppose that getDataFromDb is returning promises
getDataFromDb('myTable', name)

    .then(function(data) {
        // We got the data, but the next function is callback only
        // so we have to wrap it up with promises
        return new Promise(function(resolve) {
            getPeopleWithCallback(data, resolve);
        });
    })

    .then(function(people) {
        // We now get the people, now let's decide
        if ('good' in people) {
            return 'yeay';
        }
        // Lets clean up things first
        else {
            // Suppose that this function is returning promises
            return cleanUpPeople(people).then(function() {
                return 'yeay after clean';
            });
        }
    });

Meh. Let's write that again in Setlist.

function* yeayFunction(name) {
    // Get the data from Db (promise function)
    let data = yield getDataFromDb('myTable', name);

    // Get people with callback function
    // Setlist only accepts Promises, so we should promisify it with
    // List.async() function
    let people = yield List.async(getPeopleWithCallback)(data);

    // Lets decide
    if ('good' in people) {
        // Yeay it's good
        return 'yeay';
    }
    // You should cleaned up first
    else {
        yield cleanUpPeople(people);
        // Now it is okay to return
        return 'yeay after clean';
    }
}

RULE OF THUMB
There is always a yield keyword before calling asynchronous function and generator function.
Do not use yield when working with synchronous function.

Then, run the yeayFunction() with the run() function.

run(yeayFunction('Joe'));

Done. No more indentation hell, and of course, no callback hells.

Setlist Chain

You can chain multiple generator function execution with run(...).next().

// Chain multiple execution with .next()
run(yeayFunction('Joe'))
    .next(anotherFunction())
    .next(lastFunction());

Or, if you prefer creating new generator function, you can also call them with yield keyword. The yield keyword also pass the return value of child generator function to the parent.

// Or collect them in new generator function
function* taskList() {
    let status = yield yeayFunction('Joe');
    yield processFunction(status);
    yield lastFunction();
}
// Execute the parent generator function
run(taskList());

Wrapping Callback Functions with Promise

Setlist does not work with callback functions. So, in order to use your callback functions from the past, you can wrap them with run.promisify().

For example, the setlist promisify will wrap the file system fs.readFile() function so it can be chained in our generator function.

// Import fs library
const fs = require('fs');

// Create generator function
function* readConfig(filename) {
    // Get file content
    let content = yield run.promisify(fs.readFile)(filename);

    // Do something with it
    return processFileContent(content);
}

// Or do with promise style
run.promisify(fs.readFile)(filename)
    .then(function(content) {
        return processFileContent(content);
    });

Wrapping Class or Object with Promise

If you are planning to write down classes or objects with generator function, you can transform them into Promise on runtime by calling run.proxify() and pass in your class or object after the class definition.

For class object,it will also automatically transform the prototype object. Note that you should convert extended class with the proxify if you define new generator function in the extended class.

class baseClass {
    * method() {
        ...
    }

    static * staticMethod() {
        ...
    }
}

// Convert base class
run.proxify(baseClass);

class extendedClass extends baseClass {
    * extMethod() {
        ...
    }
}

// Convert extended class
run.proxify(extendedClass);

// No need to convert because there is no generator functions
class anotherClass extends baseClass {
    syncMethod() {
        ...
    }
}

// But this calls will return promise because we already
// transform the base class
anotherClass.staticMethod();

Create Callback Handler using Generator Function

Some function that require callback handler, such as REPL eval function, are more reliably written with generator function, at least in my opinion.

To wrap the generator function so it can be used with the callback handler you can use run.callbackify() function.

// Import REPL library
const repl = require('repl');

// Create repl eval callback handler
function* evalHandle(cmd) {
    // Get result from evaluated code
    let result;
    try {
        let result = eval(cmd);
    } catch(error) {
        // Get recoverable status (See REPL documentation from Node.js)
        if (isRecoverable(error)) {
            return REPL.Recoverable(error);
        } else {
            // You can just throw error here and the callbackify will properly
            // pass the error to the callback
            throw error;
        }
    }

    // Return result to the callback if the eval suceeds
    return result;
}

// Start repl session
repl.start({ eval: run.callbackify(evalHandle) });

Testing

You can test the package by

npm test

It may not the best testing in the world as this is my first project that using a real proper test.

Bugs

If you encounter any issues related to the Setlist library, please report them at https://github.com/withmandala/setlist/issues

License

Copyright (c) 2016 Fadhli Dzil Ikram. SetlistJS is MIT licensed.