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

vargs-callback

v0.2.4

Published

Variable arguments and "The last is the callback" convention made without "var args = somehowParse(arguments)" surrogate.

Downloads

1,407

Readme

vargs-callback Build Status

Skip to usage

The Problem

Dealing with variable function arguments makes you write some uncool boilerplate of this sort:

function openTheDoor(door, options, callback) {
    if (typeof options === 'function') {
        callback = options
        options = {}
    }
    // actual function code using parameters
    if (door.isOpen) return
    // ...
}

This parameter juggling is not what you actually want your function to do, it's just a workaround of the JavaScript function arguments implementation. There should be a way to get rid of it.

Bad Solutions

There are some libraries built to process the arguments object. It ends up with another boilerplate like this:

function openTheDoor() {
    var args = somehowParse(arguments)
    // actual function code using args object
    // note there are no argument names
    if (args.first.isOpen) return
    // ...
}

Some provide a little "arguments definition language":

function openTheDoor() {
    var args = parseArgs(['door|obj', 'options||obj', 'callback||func'], arguments)
    // actual function code using args object
    if (args.door.isOpen) return
    // ...
}

Some do weird call-twice-to-set-parameters magic forcing you to cast a spell involving this and write your code inside a callback:

function openTheDoor(door, options, callback) {
    return magicArgs(this, ['door|obj', 'options||obj', 'callback||func'], function () {
        // actual function code using declared parameters
        // note the callback around and the return statement at the beginning
        if (door.isOpen) return
        // ...
    })
}

A common problem of all these solutions is that you simply replace one boilerplate with another. You must still do some tricks before you can use the function parameters. And it clutters your code.

Good Solution

Let's talk about functions.

First, a well-designed function should not have many parameters. Having more than three parameters often means function needs refactoring. You should consider splitting the function code to several different funcitons or aggregating some of parameters into one parameter object until only small and concise functions left (Refactoring: Improving the Design of Existing Code by Martin Fowler is the book to read on the subject).

Second, there is a native JavaScript way to deal with missing parameters. All missing parameters are set to undefined and you can do something like options = options || {} to handle such cases. It is natural, it is simple and easy to read.

Finally, there is the "Callback goes last" convention which simplifies asynchronous programming. This convention creates situations when the callback takes place of one of the optional parameters. Callback taking the wrong place is the root cause of the variable arguments problem.

Combining the above, the solution comes easily. The only thing needs to be done is to move the callback to its place, leaving missing parameters undefined. This is exactly what vargs-callback does.

The library exports only one function which should be used as a decorator.

Function declarations:

var vargs = require('vargs-callback')

function openTheDoor(door, options, callback) {
    // actual function code using parameters
    // options will be undefined if only door and callback given
    if (door.isOpen) return
    // ...
}
openTheDoor = vargs(openTheDoor) // Decorate global function

Function expressions:

var vargs = require('vargs-callback')

var openTheDoor = vargs(function (door, options, callback) { // Decorate function expression
    // actual function code using parameters
    // options will be undefined if only door and callback given
    if (door.isOpen) return
    // ...
})

There is also vargs.strict decorator which forces a callback presence. It checks if the last argument is a function and throws TypeError if it's not:

var vargs = require('vargs-callback')

var handleResponse = vargs.strict(function (config, response, callback) {
    // function code
})

handleResponse('some', 'args') // TypeError: Callback is required

Note the vargs.strict call.

The Rules

Vargs is triggered on the decorated function call and does the following:

  1. If vargs.strict was used and the last argument is not a function, throw TypeError.
  2. If there are not enough arguments given and the last given argument is a function, insert undefined values into arguments just before the last element to make arguments the same size as the declared function parameter list.
  3. Call the original function with modified arguments.
  4. Do not modify arguments if there are enough arguments or the last argument is not a function.