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

timeout-flow

v0.0.18

Published

Fluent, composable, pauseable JavaScript timers and time control flows — plus RAF utilities for frame-based logic.

Downloads

45

Readme

TimeoutFlow

npm gzip size downloads GitHub stars

Fluent, human-readable time control for JavaScript.

TimeoutFlow makes working with time-based logic intuitive — think of it as a modern, composable upgrade to setTimeout and setInterval, with chaining, conditional logic, pause/resume control, retries, RAF utilities, and more.

  • Minified: ~6–7 KB
  • Gzipped: ~2–3 KB
  • Zero dependencies
  • ESM-first, tree-shakeable

Philosophy

TimeoutFlow is not just a wrapper around timers. It’s a composable toolkit for expressing time as readable logic.

Temporal behavior should be:

  • Readable — durations like "1s" and "500ms" beat magic numbers.
  • Composable — sequencing should be declarative.
  • Controllable — timers should pause, resume, cancel.
  • Branchable — real flows need if, while, label, jumpTo().
  • Tiny — no runtime bloat.

Think of TimeoutFlow as setTimeout() with superpowers.


Clean Signatures

TimeoutFlow supports both natural-language ordering and function-first ordering.

You can write:

after('1s', done);

Or:

after(done, '1s');

Both are valid.

This applies to:

  • after()
  • every()
  • debounce()
  • throttle()

Use whichever reads best in your codebase.


Installation

npm install timeout-flow

Unified Control Surface

Most time-based primitives return a controller object:

import { after } from 'timeout-flow';

function done() {
  console.log('done');
}

const ctrl = after('1s', done);

ctrl.pause();
ctrl.resume();
ctrl.cancel();
ctrl.reset?.();

console.log(ctrl.isRunning);
console.log(ctrl.isPaused);
console.log(ctrl.isFinished);

Shared by:

  • after()
  • every()
  • afterRaf()
  • everyRaf()

All controllers are:

  • Pause-safe (paused time does not count)
  • Cancel-safe
  • Monotonic-time based
  • AbortSignal-aware (where supported)

Core Primitives

after()

Run once after a delay.

import { after } from 'timeout-flow';

function greet() {
  console.log('Hello');
}

after('2s', greet);

every()

Repeat execution with optional limit.

import { every } from 'timeout-flow';

function tick(i) {
  console.log('Tick', i);
}

const ticker = every('1s', tick, { max: 5 });

debounce()

Delay execution until inactivity.

import { debounce } from 'timeout-flow';

function search(event) {
  console.log('Searching for:', event.target.value);
}

const debouncedSearch = debounce('300ms', search);

debouncedSearch.cancel();
debouncedSearch.flush();

throttle()

Limit execution frequency.

import { throttle } from 'timeout-flow';

function handleScroll() {
  console.log('scroll');
}

const onScroll = throttle('250ms', handleScroll);

onScroll.cancel();
onScroll.flush();

retry()

Retry async operations with backoff + jitter.

import { retry } from 'timeout-flow';

async function fetchData() {
  return fetch('/api/data');
}

await retry(fetchData, {
  attempts: 5,
  delay: '500ms',
  backoff: true,
  factor: 2,
  maxDelay: '5s',
  jitter: 'decorrelated'
});

waitFor()

Wait until a condition becomes true.

import { waitFor } from 'timeout-flow';

await waitFor(function checkLoaded() {
  return document.querySelector('#loaded');
}, {
  interval: '250ms',
  timeout: '5s',
  immediate: true
});

Fluent Timeline

Build declarative time flows.

import { flow } from 'timeout-flow';

function stepOne() {
  console.log('Step 1');
}

function tick(i) {
  console.log('Tick', i);
}

function finalStep() {
  console.log('Final Step');
}

flow()
  .after('1s', stepOne)
  .every('500ms', tick, { max: 3 })
  .after('1s', finalStep)
  .start();

Flow reads like a timeline and keeps duration-first ordering for readability.


AbortSignal Support

Many utilities accept { signal } for automatic cancellation.

import { after } from 'timeout-flow';

const ac = new AbortController();

function doWork() {
  console.log('Will not run if aborted');
}

after('2s', doWork, { signal: ac.signal });

ac.abort();

If already aborted at creation time, no work is scheduled.


RAF Utilities

Frame-based timing powered by requestAnimationFrame.

Ideal for visual updates, scroll handlers, layout checks, and animation loops.

Available

  • afterRaf()
  • everyRaf()
  • debounceRaf()
  • throttleRaf()
  • waitForRaf()

Example

import { throttleRaf } from 'timeout-flow';

function drawFrame() {
  console.log('draw');
}

const onScroll = throttleRaf(drawFrame);

onScroll.cancel();
onScroll.flush();

Public API

import {
  after,
  every,
  debounce,
  throttle,
  retry,
  waitFor,
  flow,

  afterRaf,
  everyRaf,
  debounceRaf,
  throttleRaf,
  waitForRaf
} from 'timeout-flow';

License

--{DR.WATT v3.0}--