πŸš€ Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more β†’
Socket
DemoInstallSign in
Socket

timeout-flow

Package Overview
Dependencies
Maintainers
1
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

timeout-flow

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

0.0.15
latest
Source
npm
Version published
Maintainers
1
Created
Source

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 added powers like chaining, conditional logic, pause/resume, retries, and more.

  • Minified: 6.64 KB
  • Gzipped: 2.6 KB

Philosophy

TimeoutFlow is not just a wrapper for setTimeout. It's a composable mini-framework for expressing time as fluent logic.

We believe temporal behavior in JavaScript should be:

  • Readable – durations like "1s" and "500ms" are easier to reason about than magic numbers.
  • Composable – sequencing events should be declarative, not a tangle of nested callbacks or timers.
  • Controllable – any timer should be pauseable, resumable, and cancelable at any moment.
  • Branchable – real flows require if, while, label, and jumpTo() β€” not just repetition.
  • Tiny – no dependencies, no bloat, and no reactivity engine required.

TimeoutFlow gives you atomic time primitives (after, every, debounce, retry) and a fluent builder (flow()) to script rich behavior over time β€” like a timeline you can control.

In Other Words:

Think of TimeoutFlow as setTimeout() with superpowers. But more importantly, think of it as a way to write time like you write logic.

flow()
  .after('1s', () => console.log('Start'))
  .every('500ms', (i) => console.log(`Tick ${i}`), 3)
  .after('1s', () => console.log('Done'))
  .start();

This isn’t about wrapping timers. It’s about orchestrating intent β€” clearly, fluently, and with full control.

Installation

npm install timeout-flow

Features

  • after("1s", fn) β€” delay execution (via AfterTimer)

  • every("500ms", fn, count?) β€” repeat execution with optional limit (via EveryTimer)

  • flow() β€” create fluent, chainable timelines with:

    • .after(), .every(), .loop(n)
    • .if(), .unless(), .label(), .jumpTo()
    • .while(), .doWhile()
  • Utilities: debounce(), throttle(), retry(), waitFor()

Usage Examples

// 1. Delayed Execution
import { after } from 'timeout-flow';
after('2s', () => console.log('Waited 2 seconds...'));

// 2. Repeating with Pause & Resume
import { every, after as wait } from 'timeout-flow';
const ticker = every('1s', i => console.log(`Tick ${i}`), 5);
wait('2.5s', () => ticker.pause());
wait('4s', () => ticker.resume());

// 3. Debounced Input
import { debounce } from 'timeout-flow';
const search = debounce('300ms', (e) => {
  console.log('Searching for:', e.target.value);
});
document.querySelector('input').addEventListener('input', search);

// 4. Retry a Failing Request
import { retry } from 'timeout-flow';
await retry(() => fetch('/api/data'), {
  attempts: 4,
  delay: '1s',
  backoff: true
});

// 5. Wait for DOM Change
import { waitFor } from 'timeout-flow';
await waitFor(() => document.querySelector('#loaded'), {
  interval: '250ms',
  timeout: '5s'
});
console.log('Element loaded!');

// 6. Fluent Timeline
import { flow } from 'timeout-flow';
flow()
  .after('1s', () => console.log('Step 1'))
  .every('500ms', (i) => console.log(`Tick ${i}`), 3)
  .after('1s', () => console.log('Final Step'))
  .start();

// 7. Conditional & Labeled Logic
let debug = true;
flow()
  .after('1s', () => console.log('Boot sequence'))
  .if(() => debug)
  .after('500ms', () => console.log('Debug logs enabled'))
  .label('loop')
  .every('1s', i => console.log(`Frame ${i}`), 3)
  .after('500ms', () => console.log('Restarting...'))
  .jumpTo('loop')
  .start();

// 8. Controlled Loop
let energy = 3;
flow()
  .doWhile(() => energy-- > 0)
  .every('400ms', () => console.log(`Blast (${energy})`))
  .after('1s', () => console.log('Energy depleted'))
  .start();

Utilities

import { debounce, throttle, retry, waitFor } from 'timeout-flow';
  • debounce('300ms', fn) β€” Run only after silence
  • throttle('1s', fn) β€” Run at most once per time window
  • retry(fn, { attempts, delay, backoff }) β€” Resilient retry for async calls
  • waitFor(() => condition, { timeout, interval }) β€” Await condition change

Frame-Based Timing (RAF Utilities)

These helpers use requestAnimationFrame under the hood to provide smooth, energy-efficient timing. Ideal for visual UI flows, canvas apps, scroll/resize behavior, and performance-sensitive interactions.

All raf utilities automatically pause in background tabs, unlike timers.

API Summary

FunctionPurposeBest For
afterRaf()Runs a function once after N ms, using requestAnimationFrame.Idle effects, UI post-load, paint batching
everyRaf()Repeats a function every N ms, throttled via frames.Sanity loops, smooth polling, visual checks
debounceRaf()Debounces a function using frames instead of timeouts.Drag/move handlers, visual updates
debounceRaf('300ms', fn)Debounces like traditional debounce, but frame-aware.Resize events, paused background flows
throttleRaf()Throttles execution to at most once per frame.Scroll events, pointermove, paint-heavy flows
throttleRaf(fn, 2)Throttles to once every 3 frames (frameSkip = 2).Advanced visuals, slower sync without timers
waitForRaf()Waits for a condition to become true using a frame-based loop.DOM readiness, layout stability, visibility checks

Key Advantages

  • Frame-sync: Triggered in sync with visual updates (60Hz or higher)
  • Background-tab safe: No CPU use when inactive
  • Energy efficient: Great for battery-conscious apps
  • Smoother UX: Especially under load or heavy visuals

πŸ›  Example Usage

import { debounceRaf } from 'timeout-flow';

const onMouseMove = debounceRaf(() => {
  drawPreview();
});

const onResize = debounceRaf('250ms', () => {
  updateLayout();
});
import { afterRaf } from 'timeout-flow';

afterRaf('2s', () => {
  showIntroAnimation();
});
import { everyRaf } from 'timeout-flow';

const loop = everyRaf('1s', () => {
  console.log('heartbeat');
});
import { throttleRaf } from 'timeout-flow';

const onScroll = throttleRaf((e) => {
  handleScroll(e);
});

const onDrag = throttleRaf(drawFrame, 2);
import { waitForRaf } from 'timeout-flow';

await waitForRaf(() => document.querySelector('#panel')?.offsetHeight > 0);

File Locations

FileDescription
raf/afterRaf.jsOne-time timer with frame pause support
raf/everyRaf.jsInterval timer using requestAnimationFrame
raf/debounceRaf.jsSmart debounce with optional duration and frame pause
raf/throttleRaf.jsInput-event throttle using frame-skip control
raf/waitForRaf.jsWaits for truthy condition using passive frame polling

License

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

Keywords

timeout

FAQs

Package last updated on 03 Jun 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts