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

futurise

v1.9.0

Published

Helpers for things that happen in the future.

Downloads

900

Readme

Futurise

🔮 Helpers for things that happen in the future.

Features

  • Event listener utilities that provide cleanup functions
  • Timer helpers with convenient registering and cleanup functions
  • Promise generators that wait for event occurrences
  • Tool to delay function calls with throttling and introspection capabilities

Usage

Everything is exported from the main entry-point through an ES6 module:

import {
  EventEmitter,
  on,
  once,
  timeout,
  interval,
  delay,
  until,
  untilOnline,
  reduceStatusList,
} from "futurise";

Installation

Install with the Node Package Manager:

npm install futurise

Documentation

Documentation is generated here.

Guide

Create an event emitter

Use EventEmitter to create a new event emitter:

import { EventEmitter } from "futurise";

const emitter = new EventEmitter<{
  A: boolean;
  B: number;
}>();

emitter.dispatchEvent("A", true);
emitter.dispatchEvent("B", 4);

It follows the EventTarget interface for adding and removing listeners:

function listener(event: boolean) {
  console.log(`Boolean value: ${event}`);
}

emitter.addEventListener("A", listener);
emitter.removeEventListener("A", listener);

Register a listener

Use on to register a listener on an element or any object that has the addEventListener and removeEventListener methods of the EventTarget interface:

import { on } from "futurise";

const off = on(element, "click", () => console.log("Clicked!"));

It returns a function that, when called, removes the listener from the element:

off();

This is convenient when used with tools that rely on cleanup functions such as the React hook useEffect:

import { on } from "futurise";
import { useEffect } from "preact/hooks";

useEffect(() => on(element, "click", () => console.log("Clicked!")), [element]);

Partial curry

The on register function can be curried by passing only the target and event name:

import { on } from "futurise";

const register = on(element, "click");

const off = register(() => console.log("Clicked!"));
const anotherOff = register(() => console.log("Another message!"));

This is convenient when using with until, a tool that returns a promise that resolves when a specific event is spotted:

import { until, on } from "futurise";

async function untilOnline(request) {
  await until(on(window, "online"));
  return request();
}

Note that futurise exports a tool untilOnline that resolve to true if it waited for the system to become online:

import { untilOnline } from "futurise";

Register once

Similar to on, once registers a listener for a given event on a target only once:

import { once } from "futurise";

// Will execute the callback only once
once(element, "click", () => console.log("Clicked!"));

Set a timer

Use timeout to execute a macro-task after a given delay:

import { timeout } from "futurise";

const cancel = timeout(1000, () => console.log("At least a second elapsed!"));

It returns a function that, when called, cancels the timer if it has not yet elapsed:

cancel();

Like for the on tool, this is convenient when used with tools that rely on cleanup functions such as the React hook useEffect:

import { timeout } from "futurise";
import { useEffect } from "preact/hooks";

useEffect(
  () => timeout(1000, () => console.log("At least a second elapsed!")),
  [],
);

Partial curry

The timeout register function can be curried by passing only the duration. Similar to currying on, it returns a register function enabling several callbacks to be registered and called once the duration elapses. Note that calling timeout immediately sets the timer:

import { timeout } from "futurise";

const register = timeout(1000);

register(() => console.log("At least a second elapsed!"));
register(() => console.log("This is called immediately after!"));
const unregister = register(() =>
  console.log("But not this, because it will be deregistered"),
);
unregister();

// After about one second, the console will show:
// > At least a second elapsed!
// > This is called immediately after!

Unregistering all callbacks clears the timeout if it did not elapse:

import { timeout } from "futurise";

const register = timeout(1000);

const unregister1 = register(() => console.log("At least a second elapsed!"));
const unregister2 = register(() => console.log("Yes, at least!"));

unregister1();
unregister2();

// The timeout is cleared

As for on, this is convenient when used together with until:

import {timeout, until} from "futurise";

async function task() {
  let done = false;
  while (!done) {
    try {
      await action();
      done = true;
    } except (error) {
      console.error(error);
      await until(timeout(1000));
    }
  }
}

Note that futurise exports a tool sleep that combines until and timeout:

import { sleep } from "futurise";

async function task() {
  await sleep(1000);
}

Set an interval

Use interval to repetitively execute a macro-task after a given interval:

import { interval } from "futurise";

const cancel = interval(1000, () => console.log("At least a second elapsed!"));

It returns a function that, when called, cancels the interval:

cancel();

Partial curry

The interval register function can be curried by passing only the duration. Similar to currying on, it returns a register function enabling several callbacks to be registered and called at each interval. Note that calling interval immediately sets the interval:

import { interval } from "futurise";

const register = interval(1000);

register(() => console.log("At least a second elapsed!"));
register(() => console.log("This is called immediately after!"));
const unregister = register(() =>
  console.log("But not this, because it will be deregistered"),
);
unregister();

// After about one second, the console will show:
// > At least a second elapsed!
// > This is called immediately after!

// After about one second later, the console will show:
// > At least a second elapsed!
// > This is called immediately after!

// And so on…

Unregistering all callbacks clears the interval:

import { interval } from "futurise";

const register = interval(1000);

const unregister1 = register(() => console.log("At least a second elapsed!"));
const unregister2 = register(() => console.log("Yes, at least!"));

unregister1();
unregister2();

// The interval is cleared

Delay calls to a function

Delaying the invocation of a callable (also known as "debouncing") can be done using the delay tool:

import { delay } from "futurise";

function doSomething(parameter) {
  heavyTaskWith(parameter);
}

const doSomethingLessOften = delay(1000, doSomething);

doSomethingLessOften(1);
doSomethingLessOften(2);
doSomethingLessOften(3);
doSomethingLessOften(4);

// Only calls `doSomething(4)` after 1 second

Immediate call

By default, the function is called after the specified duration elapsed. The immediate option enables calling the function immediately:

import { delay } from "futurise";

function doSomething(parameter) {
  heavyTaskWith(parameter);
}

const doSomethingLessOften = delay(1000, doSomething, { immediate: true });

// Calls `doSomething(1)` immediately
doSomethingLessOften(1);
doSomethingLessOften(2);
doSomethingLessOften(3);
doSomethingLessOften(4);

// Calls `doSomething(4)` after 1 second

Throttling

By default, the function is delayed until the duration elapsed before a new call is made. The throttle option enables calling the function at most once every period set by the duration:

import { delay, sleep } from "futurise";

function doSomething(parameter) {
  heavyTaskWith(parameter);
}

const doSomethingLessOften = delay(1000, doSomething, { throttle: true });

async function task() {
  doSomethingLessOften(1);
  await sleep(400);
  doSomethingLessOften(2);
  await sleep(400);
  doSomethingLessOften(3);
  await sleep(400); // Calls `doSomething(3)` while it awaits the sleep timer
  doSomethingLessOften(4);
  await sleep(1000); // Calls `doSomething(4)` while it awaits the sleep timer
}

Without the throttling mode, the function would have been called only once with doSomething(4).

Cancel pending call

The function returned by delay has a cancel() method that cancel the pending invocation:

import { delay } from "futurise";

function doSomething(parameter) {
  heavyTaskWith(parameter);
}

const doSomethingLessOften = delay(1000, doSomething);

doSomethingLessOften(1);
doSomethingLessOften.cancel();

// The function is not called

Flush the pending call

The function returned by delay has a flush() method that immediately runs the pending invocation and returns the resulting value:

import { delay } from "futurise";

function doSomething(parameter) {
  // Returns something
  return heavyTaskWith(parameter);
}

const doSomethingLessOften = delay(1000, doSomething);

doSomethingLessOften(1);
// The function is immediately called and its result is returned
const result = doSomethingLessOften.flush();

Getting the last result

The function returned by delay has a result property that is set to the value returned by the function:

import { delay } from "futurise";

function doSomething(parameter) {
  // Returns something
  return heavyTaskWith(parameter);
}

// Setting `immediate: true` to immediately execute the first invocation:
const doSomethingLessOften = delay(1000, doSomething, { immediate: true });

// The function is immediately called
doSomethingLessOften(1);
// The result can be retreived as such
const result = doSomethingLessOften.result;