@igorskyflyer/zep
Version:
π§ Zep is a zero-dependency, efficient debounce module. β°
397 lines (263 loc) β’ 9.17 kB
Markdown
<div align="center">
<img src="https://raw.githubusercontent.com/igorskyflyer/npm-zep/main/media/zep.png" alt="Icon of Zep" width="256" height="256">
<h1>Zep</h1>
</div>
<br>
<h4 align="center">
π§ Zep is a zero-dependency, efficient debounce module. β°
</h4>
<br>
<br>
## π Table of Contents
- [Features](#-features)
- [Usage](#-usage)
- [API](#-api)
- [Examples](#οΈ-examples)
- [Changelog](#-changelog)
- [Support](#-support)
- [License](#-license)
- [Related](#-related)
- [Author](#-author)
<br>
<br>
## π€ Features
- β‘ Debounce control - smartly limits how often your callback runs
- π Cancel support - stop future runs but let the current one finish
- βΉ Abort instantly - halt everything, even the running timer
- π― Event hooks - before, after, completed, cancelled, aborted, error
- π Stats tracking - logs calls, executions, and % saved
- β³ Wait detection - know when `Zep` is holding off execution
- π¦ Run state flags - check if running, waiting, cancelled, or aborted
- π‘ Error handling - custom handler for safe callback execution
- π Fluent API - chainable `.on()` methods for clean setup
- π§© Flexible timing - works with or without a debounce delay
<br>
> ### βΉοΈ NOTE
>
> #### Why `Zep()`?
>
> Because `Zep()` allows you to create time-invoked callbacks but with _deferred_ execution! `Zep()` does debouncing in a **very efficient** manner by only creating 1 Timer (\*) - provided by `setInterval`. Some use cases are: when you are processing user input but want to wait until they have finished typing or you are using a 3rd-party API that calls an event handler too often - you can throttle those calls or when your event handler does intensive computing and you want to minimize workload. It limits the rate at which a function/handler can be fired/triggered, thus increasing performance/responsiveness of your product.
>
<sub>\* other debounce functions/modules create dozens, even hundreds of Timers in order to provide the same functionality.</sub>
<br>
<br>
## π΅πΌ Usage
Install it by executing any of the following, depending on your preferred package manager:
```bash
pnpm add @igorskyflyer/zep
```
```bash
yarn add @igorskyflyer/zep
```
```bash
npm i @igorskyflyer/zep
```
<br>
<br>
## π€ΉπΌ API
### Types
```ts
type ZepCallback = (...args: any[]) => void
```
Used as a type for the callback provided in the constructor.
<br>
```ts
type ZepErrorHandler = (error: unknown) => void
```
Used as a type for the callback used in handling errors.
<br>
```ts
type ZepEventHandler = () => void
```
Used as a type for `Zep` events.
### Methods
```ts
constructor(callback: ZepCallback, time?: number): Zep
```
Creates a new instance of Zep.
- `callback` - the function/callback to debounce.
- `time` - the time limit (in **ms**) for the debouncing.
<br>
<br>
`example.ts`
```ts
import { Zep } from '@igorskyflyer/zep'
// pass an arrow function
const zep: Zep = new Zep((value: string) => {
// code to limit its execution rate
}, 1500)
function myFunction(value: string) {
/* some code */
}
// or an existing function
const zep: Zep = new Zep(myFunction, 1500)
// You can have as many arguments in your callback function as you want.
```
```ts
onCancelled(handler: ZepEventHandler): Zep
```
A handler to call when the execution of `Zep.run()` has been cancelled.
See also [`Zep.cancel()`](#zep-cancel).
```ts
onAborted(handler: ZepEventHandler): Zep
```
A handler to call when the execution of `Zep.run()` has been aborted.
See also [`Zep.abort()`](#zep-abort).
```ts
onBeforeRun(handler: ZepEventHandler): Zep
```
A handler to call before each call to your `callback`.
```ts
onAfterRun(handler: ZepEventHandler): Zep
```
A handler to call after each call to your `callback`.
```ts
onCompleted(handler: ZepEventHandler): Zep
```
A handler to call after `Zep()` has finished running, i.e. no more calls to the `Zep.run()` method have been issued in the given time-frame.
```ts
onError(handler: ZepErrorHandler): Zep
```
A handler to call when an error has occurred during execution.
<a id="zep-abort"></a>
```ts
abort(): void
```
Aborts the execution, stops Zep completely and - if applicable - the currently running Timer without waiting for it to finish its execution. See also [`Zep.cancel()`](#zep-cancel).
<a id="zep-cancel"></a>
```ts
cancel(): void
```
Stops the execution but **NOT** the current running Timer - if applicable. See also [`Zep.abort()`](#zep-abort).
```ts
run(...args): void
```
Runs the callback defined in the constructor if necessary or else debounces it.
```ts
writeStats(): void
```
Writes `Zep()` statistical information to the `console`, sample output,
> `[Zep]`: invocations: 500, callback executions: 32, saving of 93.60% calls.
β Means that the event was triggered **500** times but `Zep()` debounced it and only executed its handler **32** times instead, the handler was called **93.60%** less than without using `Zep()`.
<br>
**Properties**
```ts
executionCount: number
```
Returns the number of callback executions.
```ts
isWaiting: boolean
```
Indicates whether `Zep()` is waiting for a Timer to finish its execution, if `true`, `Zep.run()` won't create new Timers when called.
```ts
isRunning: boolean
```
Indicates whether a Timer is currently running the `callback` provided in the constructor.
```ts
wasCancelled: boolean
```
Indicates whether the execution of `Zep.run()` was cancelled. Execution can be cancelled by calling [`Zep.cancel()`](#zep-cancel).
```ts
wasAborted: boolean
```
Indicates whether the execution of `Zep.run()` was aborted. Execution can be aborted by calling [`Zep.abort()`](#zep-abort).
<br>
<br>
### ποΈ Examples
`zep.ts`
```ts
import { Zep } from '@igorskyflyer/zep'
// pass an arrow function
const zep: Zep = new Zep((value: string) => {
// code to limit its execution rate
}, 1500)
// then pass Zep's run() method to the event instead the original function
// code
const picker = vscode.window.createQuickPick()
// this is by default triggered each time a user types a character inside the QuickPick
picker.onDidChangeValue((e: string) => {
zep.run(e)
}
// due to the nature of JavaScript the following WON'T WORK,
// when you pass a class method as a parameter that
// method will get detached from the class and lose its track of <this>,
// which will be globalThis/undefined, thus resulting in an error,
picker.onDidChangeValue(zep.run)
// but you could use any of the 2 techniques
// ****
function changeHandler(): void {
zep.run()
}
// and then use that wrapper-function
picker.onDidChangeValue(changeHandler)
// ****
// or
// ****
const changeHandler: Function = zep.run.bind(zep)
picker.onDidChangeValue(changeHandler)
// ****
// by using Zep we can wait for the user to finish their input
// if they haven't typed a single letter = the onDidChangeValue wasn't
// triggered for 1500ms (1.5s) we assume they finished typing
// more code
```
<br>
<br>
## π Changelog
π The changelog is available here, [CHANGELOG.md](https://github.com/igorskyflyer/npm-zep/blob/main/CHANGELOG.md).
<br>
<br>
## πͺͺ License
Licensed under the MIT license which is available here, [MIT license](https://github.com/igorskyflyer/npm-zep/blob/main/LICENSE).
<br>
<br>
## π Support
<div align="center">
I work hard for every project, including this one and your support means a lot to me!
<br>
Consider buying me a coffee. β
<br>
<br>
<a href="https://ko-fi.com/igorskyflyer" target="_blank"><img src="https://raw.githubusercontent.com/igorskyflyer/igorskyflyer/main/assets/ko-fi.png" alt="Donate to igorskyflyer" width="180" height="46"></a>
<br>
<br>
<em>Thank you for supporting my efforts!</em> ππ
</div>
<br>
<br>
## 𧬠Related
[@igorskyflyer/scrollend-polyfill](https://www.npmjs.com/package/@igorskyflyer/scrollend-polyfill)
> _π΄ A performant and light (< 1KB) JavaScript polyfill for the scrollend Event. βΈοΈ_
<br>
[@igorskyflyer/extendable-string](https://www.npmjs.com/package/@igorskyflyer/extendable-string)
> _π¦ ExtendableString allows you to create strings on steroids that have custom transformations applied to them, unlike common, plain strings.. πͺ_
<br>
[@igorskyflyer/zing](https://www.npmjs.com/package/@igorskyflyer/zing)
> _π Zing is a C# style String formatter for JavaScript that empowers Strings with positional arguments - composite formatting. π_
<br>
[@igorskyflyer/node-clone-js](https://www.npmjs.com/package/@igorskyflyer/node-clone-js)
> _𧬠A lightweight JavaScript utility allowing deep copy-by-value of nested objects, arrays and arrays of objects. πͺ_
<br>
[@igorskyflyer/upath](https://www.npmjs.com/package/@igorskyflyer/upath)
> _π Provides a universal way of formatting file-paths in Unix-like and Windows operating systems as an alternative to the built-in path.normalize(). π§¬_
<br>
<br>
<br>
## π¨π»βπ» Author
Created by **Igor DimitrijeviΔ** ([*@igorskyflyer*](https://github.com/igorskyflyer/)).