# tm-ticker

> An interval Ticker class

Latest version **2.0.2** (published 2021-08-03) · MIT license · 0 weekly downloads

## Install

```sh
npm install tm-ticker
pnpm add tm-ticker
yarn add tm-ticker
bun add tm-ticker
```

## Health

**Score 30/100 (F)** — status: abandoned.

Positive: has types; esm support; no vulnerabilities; high quality score.

Warnings: low downloads.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 2.0.2 |
| Published | 2021-08-03 |
| First published | 2018-08-31 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 0 |
| Unpacked size | 31.4 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 3 |
| Author | Taitu Lizenbaum |
| Maintainers | taitulism |
| Keywords | interval, ticker, ticks, timer, clock, metronome, setTimeout, setInterval |

## Links

- npm: https://www.npmjs.com/package/tm-ticker
- Repository: https://github.com/taitulism/tm-ticker
- Homepage: https://github.com/taitulism/tm-ticker#readme
- Issues: https://github.com/taitulism/tm-ticker/issues
- npm.io page: https://npm.io/package/tm-ticker

## Recent versions

- 2.0.2 (latest) — 2021-08-03
- 2.0.1 — 2021-08-03
- 2.0.0 — 2021-08-02
- 1.5.1 — 2018-10-01
- 1.5.0 — 2018-09-21
- 1.2.0 — 2018-09-07
- 1.0.0 — 2018-08-31

## README

# TM-Ticker
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![Build Status](https://travis-ci.org/taitulism/tm-ticker.svg?branch=master)](https://travis-ci.org/taitulism/tm-ticker)

An accurate interval ticker class.  

&nbsp;

## TL;DR
```js
const interval = 1000;
const tickHandler = () => console.log('Tick.');

// create a simple ticker
const myTicker = Ticker.create(interval, tickHandler);

// or construct with more options
const myTicker = new Ticker({
	interval,
    tickHandler,
	tickOnStart: false,
	timeoutObj: {setTimeoutAlternative, clearTimeoutAlternative}
});

// use
myTicker.start();
myTicker.stop();
myTicker.reset();

myTicker.isTicking // boolean
myTicker.isPaused  // boolean
myTicker.timeToNextTick // ms
```

&nbsp;

## Installation
```sh
$ npm install tm-ticker
```
```js
import {Ticker} from 'tm-ticker';
```

&nbsp;

## Creation
Using the creator function:
```js
const myTicker = Ticker.create(interval?, tickHndler?);
```
Using the constructor:
```js
const myTicker = new Ticker(options?);
```

### `options`
Type: `TickerOptions`

The constructor accepts an optional object with the following properties:

* `interval: number` (optional)  
Milliseconds between ticks. **Must be greater than 50.**

* `tickHandler: function` (optional)  
The ticking callback function. Gets called on every tick.

* `tickOnStart: boolean` (default = true)  
By default, the first tick happens right on start, synchronously, before any timeout is set. Set `tickOnStart` to `false` if you want the first tick only after the first interval.

* `timeoutObj: {setTimeout, clearTimeout}` (default = globalThis)  
An object that implements both `setTimeout` and `clearTimeout` methods. Utilize this option when you want to base your ticker on alternative timeout methods ([read more](#timeoutobj)).

&nbsp;

`interval` and `tickHandler` can also be set after construction using the instance methods:
* `.setInterval(interval)`
* `.onTick(tickHandler)`

```js
const myTicker = new Ticker();

myTicker.setInterval(interval)

myTicker.onTick(tickHandler)
```

> There can be only one `tickHandler`. Setting a new tick handler will override the previous one.

&nbsp;

## Using the ticker
This part is very straight forward.

You have three main methods:
* `.start()`
* `.stop()`
* `.reset()`

and three *readOnly* properties:
* `isTicking`
* `isPaused`
* `timeToNextTick`

&nbsp;

For the following examples we'll use the same ticker that logs the word `"tick"` every second.
```js
const myTicker = new Ticker({
    interval: 1000,
    tickHandler: sayTick,
})
```

&nbsp;

### `.start()`
Start ticking. The `tickHandler` function will get called every `<interval>` milliseconds. If `tickOnStart` flag is set to `true` (default), `start` will also runs the first tick, before setting the first interval.  
When called after `.stop()` it functions as "resume", completing what's left of the interval that was stopped. There will be no start-tick in this case, regardless of `tickOnStart` state.


> NOTE: `.start()` will throw an error if called before setting an interval.



```js
myTicker.start()

/*
... 1000 ms
tick
... 1000 ms
tick
... 1000 ms
tick
...
*/
```

&nbsp;

### `.stop()`
Stop ticking (pause). Saves the interval remainder so the next call to `.start()` will continue from where it stopped.

```js
myTicker.start()
// ... 3800 ms
myTicker.stop() // remainder = 200
// ...
myTicker.start() // resume

/*
... 200 ms
tick
... 1000 ms
tick
... 1000 ms
tick
...
*/
```

&nbsp;

### `.reset()`
Resets the ticker. Calling `.reset()` while ticking does not stop the ticker. It resets the ticking starting point.  
If `tickOnStart` flag is set to `true` (default), your `tickHandler` function will get called.  

Calling `.reset()` after a `.stop()` resets the `timeToNextTick` value to zero.

```js
myTicker.start()
// ... 3800 ms
myTicker.stop() // remainder = 200

myTicker.reset() // remainder = 0

myTicker.start()

/*
... 1000 ms
tick
... 1000 ms
tick
... 1000 ms
tick
...
*/
```

You can also do:
```js
myTicker.stop().reset();
```

&nbsp;

### `.isTicking`
ReadOnly boolean.  
Toggled by `.start()` and `.stop()` methods:
```js
console.log(myTicker.isTicking) // false

myTicker.start()

console.log(myTicker.isTicking) // true

myTicker.stop()

console.log(myTicker.isTicking) // false
```

&nbsp;

### `.isPaused`
ReadOnly boolean.  
"Paused" means the ticker is stopped but hasn't been reset. 
```js
console.log(myTicker.isPaused) // false

myTicker.start()

console.log(myTicker.isPaused) // false

myTicker.stop()

console.log(myTicker.isPaused) // true

myTicker.reset()

console.log(myTicker.isPaused) // false
```

&nbsp;

### `.timeToNextTick`
ReadOnly number.  
The number of milliseconds left to next tick. Resets to zero when `.reset()` is called.
```js
myTicker.start()
// ... 5800 ms
myTicker.stop()

console.log(myTicker.timeToNextTick); // 200
myTicker.reset()
console.log(myTicker.timeToNextTick); // 0
```


&nbsp;

## Synchronizing
The main methods, `start`, `stop` and `reset`, accepts an optional `timestamp` argument.
* `timestamp` - number, optional

That is the timestamp to be considered as the method's execution time. You can pass in a timestamp when you need to syncronize the ticker with other modules.

For example, let's say we're building a stopwatch module that is based on `Ticker`. Its `startCounting` method could be something like:
```js
FancyStopWatch.startCounting = () => {
    const startedAt = Date.now();

    // doing stuff that takes 50 milliseconds to complete...

    myTicker.start(startedAt);
}
```
Without passing the `startedAt` timestamp we would loose those 50ms and the first tick would happen 1000 + 50 ms after the user clicked that imaginery `START` button.
If, for whatever reason, we don't want to loose those precious milliseconds we can utilize the `timestamp` argument.

&nbsp;

## `timeoutObj`
By default, `Ticker` internally uses the global object's `setTimeout` and `clearTimeout` methods but sometimes we might want to use alternative methods.

You can provide an object that implements those two methods ([with the same argument signatures](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout)) to be used by the ticker.

For example, let's say we want to use some kind of a `setTimeout-logger` that logs every timeout that the ticker sets. It looks like this:
```js
const myTimeoutLogger = {
    setTimeout (callback, ms, ...callbackArgs) {
        const ref = window.setTimeout(callback, ms, ...callbackArgs);

        console.log('Timeout is set');

        return ref;
    },

    clearTimeout: window.clearTimeout
}
```

To create a Ticker that uses our made up timeout-logger object we use the constructor's `timeoutObj` option:
```js
const myTicker = new Ticker({
    timeoutObj: myTimeoutLogger
});
```

&nbsp;

Check out "`timeout-worker`". [This npm module](https://www.npmjs.com/package/timeout-worker) utilizes a dedicated web-worker for setting timeouts on a separate process. This makes timeouts more accurate and steady:

```js
import { timeoutWorker } from 'timeout-worker';

timeoutWorker.start();

const myTicker = new Ticker({
    timeoutObj: timeoutWorker
});
```

&nbsp;

## Benchmark
------------
Compare TM-Ticker against vanilla `setTimeout` / `setInterval`

> Run "`npm run dev`" first.

```sh
$ npm run benchmark
```

---
_Source: https://npm.io/package/tm-ticker · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
