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 🙏

© 2026 – Pkg Stats / Ryan Hefner

wl

v0.2.1

Published

Whenable events implementation

Readme

wl - Whenable events

There are two kinds of events:

  • Reusable events which may happen many times, like a mouse click or a keypress. When subscribing to such an event, one normally does not care if an event has already been triggered in the past. One just needs to react to the event each time it happens in the future.

  • One-off events which only happen once, for instance a page load event, an ajax-request responce, a complete of a calculation delegated to a worker, or an asynchronous function callback. For this kind of events it matters if an event has already been triggered at the moment of subscription (which means there should be additional check). In latter case the listener should likely be performed immediately.

Whenable is a design pattern targeted to simplify dealing with the second kind of events by providing a special kind of listener subscriber. When using that subscriber, one does not need to worry about if an event has already been triggered, in this case the listener is invoked immediately. Additionally, the subscriber may be used several times to store additional listeners.

A good example of what could be simplified by using the Whenable solution is the page onload event. Here is how one can listen to the onload event in the traditional style:

if (document.readyState == "complete") {
    // page has already been loaded
    doWhatWeNeed();
} else {
    // preserving any existing listener
    var origOnload = window.onload || function(){};

    window.onload = function(){
        origOnload();
        doWhatWeNeed();
    }
}

The code should be performed each time a new listener should react to the onload event. Using a whenable subscriber everything above is simplified to:

window.whenLoaded(doWhatWeNeed);

The code says: call the given function doWhatWeNeed() if the page is loaded, otherwise wait until the page is loaded, and then call the function.

Listener subscribers which behave like explained above are conventionally named starting with the when.. prefix and followed by a past participle describing an event: whenLoaded(), whenCompleted(), whenFailedToLoad() and so on. The Whenable term is also used to refer to a one-off event supporting this kind of subscription.

Whenable pattern was inspired by Promises, and it is similar to Promises in that it also allows not to care about when an event actually fires. But unlike Promises, Whenable is much easier to use and understand, produces simplier code, and is more general solution thus covering a wider range of use-cases.

This wl library implements the Whenable object, which represents such an event and can be used to easily produce a whenable-style subscriber.

Installation

For the web-browser environment — download the distribution, unpack it and load the wl.js in a preferrable way. That is an UMD module, thus for instance it may simply be loaded as a plain JavaScript file using the <script> tag:

<script src="wl/wl.js"></script>

For Node.js — install wl with npm:

$ npm install wl

and then in your code:

var wl = require('wl');

Optionally you may load the script from the distribution:

var wl = require('path/to/wl.js');

After the module is loaded, the wl.Whenable() constructor is available.

Usage

Constructing a Whenable event is simple:

var myWhenable = new wl.Whenable;

The object has the two methods. The emit() method fires the event and invokes the subscribed listeners:

myWhenable.emit();

The getSubscriber() method returns a whenable-style subscriber function:

var whenEventTriggered = myWhenable.getSubscriber();

The subscriber may later be reused to subscribe a listener to the event:

whenEventTriggered(myListener);

The myListener() will be invoked after the event is triggered. If the event has already been triggered at the moment of subscription, the listener is called immediately (yet asynchronously in order to keep the flow consistent).

The methods of the Whenable object (along with the Whenable instance itself) are not supposed to be exposed to the event user. Normally the Whenable event is stored private and is emitted by internal means. Instead the whenable subscriber function (returned by the getSubscriber() method) is to be provided to the user so that he can attach listeners to the event.

When subscribing a listener, the context may be provided as a second argument:

whenEventTriggered(myObject.someMethod, myObject);

Upon the event is triggered, the subscribed listeners are executed in their respective contexts (if provided upon subscription).

Additionally, the emit() method may take any set of arguments which are simply forwarded as the arguments provided to the subscribed listeners. This allows to supply the listeners with some details about the event:

myWhenable.emit(result);

Examples

Here is an ordinary asynchronous function which executes a callback after some time:

var doSomething = function(cb) {
    setTimeout(cb, 1000);
}

Let us create a Whenable event representing the function completion:

var somethingWhenable = new wl.Whenable;

var initiateSomething = function() {
    doSomething(function() {
        somethingWhenable.emit();
    });
}

var whenSomethingDone = somethingWhenable.getSubscriber();

Now there are the two functions:

  • initiateSomething() starts the process which should lead to the event emission in the future, and

  • whenSomethingDone(), the whenable-style subscriber which may subscribe as many listeners as needed, before or after the event is emitted.

Those two functions may now be used separately.

Similarly, if there is an asynchronous routine with two outcomes, one may prepare the two whenable events:

var doSomething = function(successCb, failureCb) {
    var cb = function() {
        try {
            // do something that may fail
            ...
        } catch(e) {
            return failureCb();
        }

        successCb();
    }

    setTimeout(cb, 1000);
}
var success = new wl.Whenable;
var failure = new wl.Whenable;

var initiateSomething = function() {
    doSomething(
        function(){success.emit();},
        function(){failure.emit();}
    );
}

var whenSomethingSucceded = success.getSubscriber();
var whenSomethingFailed = failure.getSubscriber();

The code above provides the similar initiator function initiateSomething(), and the two whenable subscribers, whenSomethingSucceeded() and whenSomethingFailed() which subscribe a provided listener to the success or failure outcomes respectively.

Another example: here is the implementation of the magic window.whenLoaded() subscriber given in the beginning of this text. The subscriber is used to react to the page load event:

var onloadWhenable = new wl.Whenable;

if (document.readyState == "complete") {
    // already loaded
    onloadWhenable.emit();
} else {
    // preserving existing listener
    var origOnload = window.onload || function(){};

    window.onload = function(){
        origOnload();
        onloadWhenable.emit();
    }
}

window.whenLoaded = onloadWhenable.getSubscriber();