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

deferium

v0.3.0

Published

A framework for working with higher level async types.

Downloads

29

Readme

Deferium

Events, promises and asynchronous operations simplified! Through a few useful and composable primitives, Deferium gives you a toolbox to greatly simplify the handling and organisation of complex time-dependent and asynchronous processes.

By providing a suite of classes to extend native Promise functionality, Deferium allows developers to manage asynchronous tasks with greater control and clarity. Whether you're dealing with deferred execution, timeouts, progress tracking, or complex promise chains, Deferium offers a structured approach to make your asynchronous code more readable and maintainable by easing application of modern async/await syntax.

Concepts

Traits

Deferium exposes a few Trait classes that you can use or derive from or that you can compose together to make your asynchronous operations/classes more semantically understandable and concise. Deferium is heavily class based and targeted for developers seeking an object oriented approach to complex state management.

The core traits Deferium defines and aids with are the following:

  • Awaitability
  • Cancellability
  • Memory-Leakability
  • Streamability
  • Subscribability

By providing composable base classes that already contain a lot of logic around these mentioned semantic elements it's easy to compose more complex classes that are Awaitable, Cancellable and Streamable at the same time.

Name-Mapping

As most of the traits are pretty universal, it may be desired to specify more specific names for methods and properties of these traits. When talking about processes in general, for example you may not want to reject a process, but rather abort it.

Deferium allows you to do that, without losing the logic behind the base types through its NameMapped types.

Through an abstraction layer, these traits can still be handled naming-independently by Frameworks, but adopt the specific semantics of your use case.

To Name-Map a type, just use its NameMappedX equivalent, if provided. More information will follow later.

Project status

This project is in early alpha.

Installation

To get started with Deferium, install the package using npm:

npm install deferium

Or using yarn:

yarn add deferium

Usage

Awaitable Types

If you ever tried to derive from a Promise directly you will know that it's not easy. The Awaitable types solve that problem and add additional logic.

Awaitable is an easily derivable drop-in-replacement for Promise.

Use it standalone:

class Process
{
    public completion = new Awaitable();

    ...
    onCompletion()
    {
        this.completion.resolve();
    }
    ...
}

Or use it as a base class:

class Process extends Awaitable
{
    ...
    onCompletion()
    {
        this.resolve();
    }
    ...
}

const FindNeedleInHaystack = new Process()

await FindNeedleInHaystack;

if(!FindNeedleInHaystack.isResolved)    //This is one of the properties that automatically gets updated
    console.log("Still searching");

console.log("Medal of Honour");

Cancellable Types

In many asynchronous operations, there is a need to abort an ongoing task before it naturally completes. The Cancellable types in Deferium provide a structured way to handle such scenarios, allowing you to not only initiate cancellation but also to react to it within your asynchronous workflows.

A Cancellable type extends the basic Promise functionality with methods to cancel the operation, check if it has been cancelled, and specify a cancellation reason. This makes it easier to manage resources and avoid potential memory leaks by cleaning up after a task that is no longer needed.

Here's how you can use a Cancellable type:

class LongRunningProcess extends Cancellable {
    constructor() {
        super();
        // Start the process
    }

    // Method to initiate the cancellation
    abortProcess() {
        this.cancel("Process was aborted by the user.");
    }
}

// Usage
const process = new LongRunningProcess();

// At some point later, if you need to abort the process:
process.abortProcess();

// You can check if the process was cancelled:
if (process.isCancelled) {
    console.log(`Process cancelled: ${process.cancelReason}`);
}

The Cancellable type ensures that your asynchronous operations are robust and respect the lifecycle of your application, preventing unintended side effects when operations are no longer relevant.

Remember to handle the cancellation in your asynchronous tasks through an override of the respective functions to properly free up resources and avoid executing further logic after the cancellation has been requested.

For more advanced use cases, you can combine Cancellable with other traits provided by Deferium to create complex types that are both awaitable and cancellable, among other things.

Streamable Types

Streamable types in Deferium provide a way to handle a sequence of asynchronous events or data chunks over time, similar to how streams work in many programming environments. These types are particularly useful when dealing with data that is not available all at once, allowing you to process each piece of data as it arrives.

A Streamable type typically includes methods to push data into the stream, subscribe to data events, and handle the end of the stream or errors that may occur during data processing.

Here's a basic example of how a Streamable type might be used:

class DataStreamer extends Streamable<string> {
    constructor() {
        super(); // Initialize the stream
    }

    pushData(data: string) {
        //...customizable logic
        this.emit(data);
    }

    endStream() {
        //...customizable logic
        this.close();
    }
}

async logStream()
{
    for await (const chunk of dataStreamer)
        console.log(stream);
}

// Usage
const dataStreamer = new DataStreamer();

logStream();

// Synchronous as well as asynchronous emissions to the stream are handled without losses
dataStreamer.pushData("First");
dataStreamer.pushData("Second");
await Delay.for(1000);
dataStreamer.pushData("Third");

dataStreamer.endStream();

The Streamable type allows you to build responsive and efficient data processing mechanisms that can handle real-time data, streams of API responses, or any other form of sequential data.

Subscribable Types

Subscribable types in Deferium provide a pattern for creating objects that other parts of your application can listen to for events or changes. This pattern is commonly used in event-driven programming and can help decouple the components of your system by allowing them to communicate through well-defined events.

A Subscribable type typically includes methods to subscribe to events, unsubscribe from events, and emit events to notify all current subscribers. This pattern is useful for creating custom events, implementing observer patterns, or simply for allowing parts of your application to react to changes in state or other significant occurrences.

Here's a basic example of how a Subscribable type might be used:

class EventHub
{
    ...
    public onMessage = new Subscribable();
    ...
}

// Usage
const dispatcher = new EventHub();

// Function to handle events
function eventHandler(data) {
    console.log(`Event received with data: ${data}`);
}

dispatcher.onMessage.subscribe(eventHandler);
dispatcher.onMessage.emit('Hello, Subscribers!');

// Unsubscribe from the 'customEvent' event
dispatcher.onMessage.unsubscribe(eventHandler);

The Subscribable type is a utility type for managing and coordinating events within your application.

The Subscribable type can of course also be derived from to have more customized subscriber management etc. or name mapped methods and members.

Memory-Leakable Types

Memory-Leakable Types The MemoryLeakable type in Deferium provides a unified interface to build disposable objects that need explicit cleanup to avoid memory leaks. This is useful for event handler subscriptions, database connections, network sockets, file handles, etc. that can leak if not properly closed.

A MemoryLeakable type has a dispose() method that should be called to clean up any resources when the object is no longer needed. It also exposes isDisposed to check if disposal has occurred.

Here is an example:

class DatabaseConnection extends MemoryLeakable {
  constructor() {
    super();
    this.handle = db.open(...)
  }
}

const db = new DatabaseConnection();

// use database 

db.dispose(); // avoid memory leak

The MemoryLeakable type ensures you build classes that cleanly free resources, avoiding hard-to-debug memory leaks. It enforces that disposal logic is implemented.

For advanced cases, you can combine with other Deferium types like Awaitable to make classes awaitable and disposable.

More coming soon...

Contributing

Contributions are welcome! If you have a feature request, bug report, or a pull request, please feel free to contribute to the project.

License

Deferium is open-sourced software licensed under the MIT license.