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

tasktimer

v4.0.0

Published

An accurate timer utility for running periodic tasks on the given interval ticks or dates.

Readme

This module is ESM 🔆. Please read this.

An accurate timer utility for running periodic tasks on the given interval ticks or dates — with a single timer instance, zero runtime dependencies, and full TypeScript types.

📖  Full documentation & guides:  onury.io/tasktimer

[!TIP] v4 is a 2026 modernization — ESM-only, zero-dependency, browser-safe, drift-free precision — that also squashed some long-standing bugs and made API improvements, plus new sugar: leading-edge runs (lead), typed task data, typed events, coded errors (TaskTimerError), and silentErrors.  What's changed →

Why TaskTimer?

Because of the single-threaded, asynchronous nature of JavaScript, each execution takes a slice of CPU time, and the wait before the next one varies with the load. This creates a cumulative latency in naive timers that gradually drifts away from the intended schedule. TaskTimer corrects this drift on every tick, and it lets you run many tasks — each on its own interval, run limit, or date window — from a single timer.

Features

  • Precision (on by default): the delay between ticks is auto-adjusted when it drifts due to task/CPU load or clock drift. It uses the monotonic performance.now() (drift-free, in Node and the browser) and auto-recovers via immediate ticks after a blocking task.
  • Run or schedule multiple tasks on a single timer instance.
  • Sync or async tasks — return a Promise or use the done() callback.
  • Limit runs per task (totalRuns), add an initial delay (tickDelay), run on the leading edge (lead), or bind a task to a date window (startDate / stopDate).
  • Attach arbitrary data to a task — typed via Task<TData>.
  • Add, remove, reset, enable/disable, pause and resume tasks at any time — without recreating the timer.
  • Stateful: auto-stop when all tasks complete (stopOnCompleted); free memory when a task finishes (removeOnCompleted).
  • A familiar, typed EventEmitter surface (on / once / off / emit …) — listeners get a typed event.
  • Coded errors — every throw is a TaskTimerError with a stable err.code; opt out of swallowing task errors with silentErrors.
  • ESM-only, zero runtime dependencies, runs in Node and the browser, written in TypeScript.

Installation

npm i tasktimer
import { TaskTimer, Event, State } from 'tasktimer';

Event, State, Task, TaskTimerError and ErrorCode are all named exports (there is no TaskTimer.Event namespace).

[!NOTE] TaskTimer is ESM-only. It runs in Node and the browser via native ESM or a bundler (Vite, esbuild, Rollup, webpack …) — precision uses the universal performance.now(), and setImmediate falls back to setTimeout off-Node.

Usage

Simplest example

const timer = new TaskTimer(1000); // base interval: 1000 ms
timer.add(task => console.log(`Run #${task.currentRuns}`)).start();

A plain timer (events only, no tasks)

const timer = new TaskTimer(5000);
timer.on(Event.TICK, () => console.log(`Tick #${timer.tickCount}`));
timer.start();

Multiple tasks on a single timer

const timer = new TaskTimer(1000); // 1s base resolution

timer.add([
    {
        id: 'task-1',
        tickInterval: 5,  // every 5 ticks → 5s
        totalRuns: 10,    // run 10 times only (0 = unlimited)
        callback(task) {
            console.log(`${task.id} ran ${task.currentRuns} times`);
        }
    },
    {
        id: 'task-2',
        tickDelay: 1,     // wait 1 tick before the first run
        tickInterval: 10, // every 10 ticks → 10s
        totalRuns: 2,
        callback(task) {
            console.log(`${task.id} ran ${task.currentRuns} times`);
        }
    }
]);

timer.on(Event.TICK, () => {
    console.log(`tick ${timer.tickCount} · elapsed ${timer.time.elapsed} ms`);
});

timer.start();

Async tasks

// return a Promise
timer.add(task => fetch(url).then(handle));

// or call done() when finished
timer.add((task, done) => {
    fs.readFile(path, () => done());
});

[!TIP] Set defer: true on a task to defer its callback to the next event-loop turn (via setImmediate) — useful when the task synchronously blocks the event loop without doing I/O. Set lead: true to run a task once immediately on start() (the leading edge), instead of waiting a full interval.

Auto-stop when everything completes

const timer = new TaskTimer({ interval: 1000, stopOnCompleted: true });

timer.add({ totalRuns: 3, callback: doWork });
timer.add({ totalRuns: 5, callback: doOtherWork });

timer.on(Event.COMPLETED, () => console.log('all tasks done'));
timer.start();

Pause and resume

timer.start();
timer.pause();   // holds all tasks
timer.resume();  // continues where it left off
timer.stop();    // stops; tasks and counters are retained
timer.reset();   // back to idle; tasks removed silently

How it works

  • You create a timer with a base interval (e.g. 1000 ms) — the tick resolution shared by all tasks.
  • You add tasks that run on tick intervals (e.g. every 5th tick), optionally with a run limit, an initial delay, or a start/stop date.
  • Beyond task callbacks, you can listen for lifecycle events (tick, task, completed, …).
  • Tasks can be added, removed, reset, enabled or disabled at any time; the timer can be paused and resumed — all without recreating it.

API

new TaskTimer(options?)

options is either an ITaskTimerOptions object or a number (the base interval in ms).

Timer properties

| Property | Type | Description | | --- | --- | --- | | interval | number | Base tick interval in ms (read/write). | | precision | boolean | Whether drift auto-correction is enabled (read/write). | | stopOnCompleted | boolean | Auto-stop once all tasks complete (read/write). | | silentErrors | boolean | Swallow task errors with no taskError listener; false surfaces them (read/write). | | state | State | Current timer state (read-only). | | time | ITimeInfo | { started, stopped, elapsed } for the current run (read-only). | | tickCount | number | Ticks elapsed in the current run (read-only). | | taskCount | number | Number of tasks (read-only). | | tasks | Task[] | All tasks, in insertion order (read-only). | | taskRunCount | number | Total task executions (read-only). | | runCount | number | Total timer runs, including resumes (read-only). |

Timer methods

| Method | Returns | Description | | --- | --- | --- | | add(task) | TaskTimer | Add a task, options, callback, or an array of these. | | get(id) | Task \| undefined | Get a task by id (undefined if absent). | | remove(task) | TaskTimer | Remove a task by id or instance. | | start() | TaskTimer | Start (or restart) the timer. | | pause() | TaskTimer | Pause the timer and all tasks. | | resume() | TaskTimer | Resume a paused timer (starts it if idle). | | stop() | TaskTimer | Stop the timer, retaining tasks and counters. | | reset() | TaskTimer | Stop and reset to idle, removing all tasks silently. |

TaskTimer also exposes the EventEmitter surface: on / addListener, once, off / removeListener, removeAllListeners, emit, listeners, listenerCount, eventNames.

new Task(options)

A Task is created implicitly via timer.add(...), or explicitly with the constructor (an ITaskOptions with a required id and callback).

| Member | Type | Description | | --- | --- | --- | | id | string | Unique task id (read-only). | | enabled | boolean | While false, the task bypasses its callback (read/write). | | tickDelay | number | Ticks to wait before the first run (read/write). | | tickInterval | number | Tick interval the task runs on (read/write). | | totalRuns | number \| null | Run limit; 0/null = unlimited (read/write). | | defer | boolean | Defer the callback to the next event-loop turn via setImmediate (read/write). | | lead | boolean | Run once immediately on start() (the leading edge) (read/write). | | removeOnCompleted | boolean | Remove the task once completed (read/write). | | data | TData | Arbitrary user data attached to the task (read/write). | | currentRuns | number | Number of times run so far (read-only). | | completed | boolean | Whether the task is completed (read-only). | | time | ITimeInfo | The task's lifetime { started, stopped, elapsed } (read-only). | | callback | TaskCallback | The callback executed on each run (read-only). | | reset(options?) | Task | Reset the run count, optionally re-configuring (id can't change). |

Enumerations

All are named exports: import { State, Event, ErrorCode } from 'tasktimer'.

StateIDLE · RUNNING · PAUSED · STOPPED.

ErrorCode — the code on a thrown TaskTimerError: NO_TASK_PROVIDED · TASK_ID_REQUIRED · CALLBACK_REQUIRED · DUPLICATE_TASK_ID · NO_SUCH_TASK · INVALID_DATE_RANGE · CANNOT_CHANGE_ID · TASK_ERROR.

Event — the events emitted by the timer:

| Event | Value | Emitted when | | --- | --- | --- | | TICK | tick | Each tick of the timer. | | STARTED | started | The timer is started. | | RESUMED | resumed | The timer is resumed. | | PAUSED | paused | The timer is paused. | | STOPPED | stopped | The timer is stopped. | | RESET | reset | The timer is reset. | | TASK | task | A task is executed. | | TASK_ADDED | taskAdded | A task is added. | | TASK_REMOVED | taskRemoved | A task is removed. | | TASK_COMPLETED | taskCompleted | A task completes its runs / reaches its stopDate. | | TASK_ERROR | taskError | A task throws or rejects. | | COMPLETED | completed | Every task has completed. |

Event listeners receive a typed ITaskTimerEvent: { name, timer, task?, error? }. The related task is event.task and the timer is event.timer — on every event, including taskError.

Types

ITaskTimerOptions

{ interval?, precision?, stopOnCompleted?, silentErrors? }

ITaskOptions<TData>

{ id?, enabled?, tickDelay?, tickInterval?, totalRuns?, startDate?, stopDate?, defer?, lead?, removeOnCompleted?, data?, callback }

ITimeInfo

{ started, stopped, elapsed } — timestamps and elapsed time in ms.

ITaskTimerEvent

{ name, timer, task?, error? }

TaskCallback<TData>

(task: Task<TData>, done?: () => void) => void | Promise<unknown>

Full reference: onury.io/tasktimer.

Changelog

See CHANGELOG.md. Migrating from v3? See the migration notes — v4 is ESM-only, drops the TaskTimer.Event namespace for named exports, and reshapes the event payload.

Other Projects

  • AccessControl — Role and Attribute based Access Control for Node.js.
  • Configuard — Turn flat config rows from a database table into a nested, typed configuration object — with ${...} templating and accessor-based (ABAC) filtering.
  • Notation — Read, modify, and filter the contents of objects and arrays via dot/bracket notation strings or glob patterns.

License

© 2026, Onur Yıldırım. MIT License.