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

good-clock

v1.2.0

Published

An intuitive timer / clock for javascript + typescript

Downloads

5

Readme

good-clock

An intuitive timer / clock for javascript + typescript

Install

npm i good-clock

Quick Links

Getting Started

Setup

import Clock from 'good-clock'       // for import method
const Clock = require('good-clock')  // for require method

Create a clock object - ( or multiple if you want )

const clock = new Clock

Classic "setInterval" method

clock.start(() => {
  console.log('tick-tock')
}, 1000)

Dot Notation method

clock.setCallback(() => { console.log('tick-tock') })
clock.setTimeInterval(1000)
clock.start()

Things get fun

clock.start((value) => {
  console.log(value)
}, clock.seconds(1), {
  {
    startValue: 10,
    endValue: 20,
    endCallback: () => {
      console.log("all done!")
    }
  }
})

Everything works using both methods, this will do the same thing

clock.setCallback((value) => { console.log(value) })
clock.setTimeInterval(clock.seconds(1))
clock.setStartValue(10)
clock.setEndValue(20)
clock.setEndCallback(() => { console.log("all done!") })
clock.start()

Clock Details

Each clock object contains one "clock" and one "wait". The clock acts like javascript's setInterval and the wait acts like javascript's setTimeout. Why use them? They have some awesome additions that make them more intuitive and quicker to implement. The clock has a built in value state which increments or decrements on every clock tick and is automagically passed to the clock's callback function. Unlike javascript's setInterval, you can change the clock's callback function entirely and the next tick will call the new callback.

The most important difference to realize is that good-clock is object oriented! You have to create a new clock object for every different clock you want to use. Calling clock.start(function) will NOT create a new clock, it only starts the clock its acting on. Each good-clock instance only has ONE wait as well! For example, if you want two timers you DO NOT DO THIS:

// BAD TWO CLOCK IMPLEMENTATION
// DO NOT DO THIS!!!

const clock = new Clock

clock.start(() => {
    someFunction()
})

clock.start((value) => {
    someOtherFunction(value)
})

Instead do this:

// GOOD TWO CLOCK IMPLEMENTATION
// DO THIS

const clockOne = new Clock
const clockTwo = new Clock

clockOne.start(() => {
    someFunction()
})

clockTwo.start((value) => {
    someOtherFunction(value)
})

Actions

| code | description | options | |--|--|--| | clock.increment() | Increments the clock's value by one valueInterval or by the optional argument | number: the amount to increment the clock's value. (optional) | | clock.decrement() | Decrements the clock's value by one valueInterval or by the optional argument | number: the amount to decrement the clock's value. (optional) | | clock.start() | Starts the clock, optionally sets it up. | function: see clock.setCallback() below. number: see clock.setTimeInterval() below. ClockOptions: see ClockOptions below. | | clock.stop() | Stops the clock and resets it to startValue | none | | clock.stopAfterNextCallback() | Stops the clock after the next clock tick and resets it to startValue. | none | | clock.pause() | Pauses the clock. Does NOT change the clock's value and clock.resume() can then be used to restart the clock as if it had never stopped. | none | | clock.pauseAfterNextCallback() | Pauses the clock after the next clock tick. Does NOT change the clock's value and clock.resume() can then be used to restart the clock as if it had never stopped. | none | | clock.resume() | Restarts the clock without changing it's value. Remember that clock.stop() resets the value to the clock's startValue. So if you use clock.stop() to stop the clock and then resume to restart the clock, the clock WILL start at the clock's startValue. Use clock.pause() to stop a clock without reseting it's value to it's startValue. | none | | clock.wait() | Calls a function after a determined wait time. | function: The function to be called after the wait time. number: The time to wait before calling the function. | | clock.cancelWaitWithCallback() | Call this when the clock is waiting from clock.wait() to cancel the wait and immediately call its function. | none | | clock.cancelWaitWithoutCallback() | Call this when the clock is waiting from clock.wait() to cancel the wait and NOT call its function. | none |

ClockOptions: type: object ( all properties are optional )

{
    valueInterval: number,
    incrementing: boolean,
    decrementing: boolean,
    startValue: number,
    startCallback: function,
    endValue: number,
    endCallback: function,
    clampEndValue: boolean,
    skipInitialCallback: boolean,
    incrementBeforeCallbacks: boolean,
    incrementBeforeInitialCallback: boolean,
    driftCorrectionOn: boolean
}

For more details on ClockOptions see the corresponding setters below.

Setters

| code | description | |--|--| | clock.setCallback(function(value)) | Sets the callback of the clock. This is a function that's called on every clock tick. The function receives the clock's value as an argument. | | clock.setValue(number) | Sets the value of the clock. This can be any number. The value will be incremented or decremented every clock tick based on the clock's valueInterval. | | clock.setTimeInterval(number) | Sets the time interval of the clock in milliseconds. The clock is based on javascript's setTimeout function, so the time between clock callbacks is NOT perfectly precise. This time can vary quite a bit, sometimes 50ms or so. Each lag (or inaccurately triggered interval) adds on top of the last. So a clock with it's timeInterval set to 1000, (1 second) after 120 seconds (2 minutes) will be more like 120.5 or 121 seconds later. If you want the clock to sync with real world seconds / minutes / etc... see the clock.setDriftCorrection() method. | | clock.setValueInterval(number) | Sets the amount to increase or decrease the clock's value on every clock tick. Whether it adds or subtracts is based on whether the clock is set to increment or decrement. | | clock.setIncrementing(boolean or undefined) | If called without an argument or with true the clock will be set to increment. If called with false the clock will be set to decrement. | | clock.setDecrementing(boolean or undefined) | If called without an argument or with true the clock will be set to decrement. If called with false the clock will be set to increment. | | clock.setStartValue(number) | Sets the clock's start value. When calling clock.start() the clock will start at this value. If startValue is not set and clock.start() is called the clock will start with whatever clock.value is set as, and startValue will be automatically set to the clock.value. | | clock.setStartCallback(function) | Sets a function that is called when clock.start() is called. | | clock.setEndValue(number) | Set's the endValue of the clock. If the value is equal to this endValue, the clock will automatically stop. If clock.isEndValueClamped is true then the clock will also stop if it is greater than (when incrementing) or less than (when decrementing) this endValue. | | clock.setEndCallback(function) | Sets a function that is called when the endValue causes the clock to stop. | | clock.setClampEndValue(number) | Sets the value that the clock will automatically stop at (endValue). If clock.isEndValueClamped is true then the clock will also stop if it is greater than (when incrementing) or less than (when decrementing) the endValue. | | clock.setSkipInitialCallback(boolean) | Sets whether or not the clock's first tick is when clock.start() is called, or one timeInterval after clock.start() is called. | | clock.setIncrementBeforeCallbacks(boolean) | Sets whether or not the clock's value will increment / decrement before or after each callback. | | clock.setIncrementBeforeInitialCallback(boolean) | Sets whether or not the clock's value will increment / decrement before the first clock tick. | | clock.setDriftCorrection(boolean) | The clock is based on javascript's setTimeout function, so the time between clock callbacks is NOT perfectly precise. This time can vary quite a bit, sometimes 50ms or so. Each lag (or inaccurately triggered interval) adds on top of the last. So a clock with it's timeInterval set to 1000, (1 second) after 120 seconds (2 minutes) will be more like 120.5 or 121 seconds later. If you want the clock to sync with real world seconds / minutes / etc... set this to true. Note that the clock will still not fire at precisely the right time, this only ensures that the clock's error will not accumulate. If the clock's drift is greater than 50ms, driftCorrection is automatically disabled. If the clock's timeInterval is set to less than 50ms, driftCorrection is automatically disabled. |

Getters

| code | description | type | |--|--|--| | clock.value | The value of the clock. | number | | clock.timeInterval | The time interval of the clock. | number | | clock.valueInterval | The value interval of the clock. The value interval is how much the value will change each clock tick. | number | | clock.isIncrementing | true if the clock is set to increment, false if set to decrement. | boolean | | clock.isDecrementing | true if the clock is set to decrement, false if set to increment. | boolean | | clock.startValue | The value the clock will start at when ran with clock.start(). It is undefined until either directly set or the first time clock.start() is called. The first time clock.start() is called, it's startValue will be set to whatever the value was. (default = 1). Calling clock.stop() will set the clock's value back to this startValue. Calling clock.start() again, will start the clock at this startValue. | number | | clock.endValue | The clock will automatically stop once the clock's value equals this value. | number | | clock.isEndValueClamped | true if the clock is set to be clamped to the end value. false if not. (default = false) | boolean | | clock.isSkippingInitialCallback | true if the clock is set to skip the initial callback when clock.start() is called. false if not. (default = false) | boolean | | clock.isIncrementingBeforeCallbacks | true if the clock is set to increment / decrement before each callback instead of after. false if not. (default = false) | boolean | | clock.isIncrementingBeforeInitialCallback | true if the clock is set to increment before the initial callback. false if not. | boolean | | clock.isDriftCorrectionOn | true if drift correction is on. false if not. (default = false) | boolean | | clock.isRunning|trueif the clock is running.falseif not. | boolean | |clock.isPaused|trueif the clock is paused.falseif not. | boolean | |clock.isStopped|trueif the clock is stopped.falseif not. | boolean | |clock.isWaiting|trueif the clock'sclock.wait()is waiting.falseif not. | boolean | |clock.isAtStart|trueif the clock's value is equal to the clock's startValue.falseif not. | boolean | |clock.isAtEnd|trueif the clock's value is equal to the clock's endValue.falseif not. | boolean | |clock.willStopAfterNextCallback|trueif the clock is set to stop after the next callback afterclock.stop()is called.falseif not. | boolean | |clock.willPauseAfterNextCallback|trueif the clock is set to pause after the next callback afterclock.pause()is called.falseif not. | boolean | |

Helpers

| code | description | |--|--| | clock.seconds(number) | Returns milliseconds. (input * 1000) | | clock.minutes(number) | Returns milliseconds. (input * 60 * 1000) | | clock.hours(number) | Returns milliseconds. (input * 60 * 60 * 1000) |

Examples

Simple count to ten and stop, incrementing by one each second.

clock.start((value) => {
    console.log(value)
}, clock.seconds(1), {
	endValue: 10,
})

Count to ten, each one second, but pause at 5 for 3 seconds

clock.start((value) => {
    console.log(value)
    if (value === 5) {
	    clock.pause()
	    clock.wait(() => {
		    clock.resume()
		}, clock.seconds(3))
	}
}, clock.seconds(1), {
	endValue: 10,
})

Easy decrementing

clock.start((value) => {
    console.log(value)
}, clock.seconds(1), {
	decrementing: true,
	endValue: -10,
})

Start at 15 and count to 20

clock.start((value) => {
    console.log(value)
}, clock.seconds(1), {
	startValue: 15,
	endValue: 20,
})

Pass the endValue, but since it's clamped it stops at the endValue

clock.start((value) => {
    console.log(value)
}, clock.seconds(1), {
	valueInterval: 3,
	endValue: 10,
	clampEndValue: true,
})

Change the value interval mid-flight

clock.start((value) => {
    clock.setValueInterval(value + 1)
    console.log(value)
}, clock.seconds(1), {
	endValue: 20,
})

Change the callback function mid-flight ( after 5 second wait )

clock.start((value) => {
	console.log(value)
}, clock.seconds(1), {
	endValue: 10,
})

clock.wait(() => {
	clock.setCallback((value) => {
		console.log("value: " + value)
	})
}, clock.seconds(5))

Defaults

callback = null
value = 0
timeInterval = 1000
valueInterval = 1
incrementing = true
decrementing = false
startValue = undefined
startCallback = null
endValue = undefined
endCallback = null
clampEndValue = false
skipInitialCallback = false
incrementBeforeCallbacks = false
incrementBeforeInitialCallback = false
isRunning = false
isPaused = false
isStopped = true
waitCallback = null
isWaiting = false
willStopAfterNextCallback = false
willPauseAfterNextCallback = false

Improvements

If you would like to contribute improvements please create issues or create pull requests on the github page.