Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .github/workflows/publish-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,28 @@ on:
types: [published]

jobs:
test:
name: Test
uses: ./.github/workflows/test.yml

publish-npm:
name: Publish to npm registry

needs: [test]

runs-on: ubuntu-latest

permissions:
id-token: write

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup node
uses: actions/setup-node@v4
with:
node-version: 18.x
node-version: 22.x
registry-url: https://registry.npmjs.org/

- name: Install dependencies
Expand Down
26 changes: 26 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Test Node.js

on: [push, workflow_call]

jobs:
test:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [18.x, 20.x, 22.x, 24.x]

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Node.js v${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'

- name: Test for Node.js v${{ matrix.node-version }}
run: |
npm install
npm run test
1 change: 1 addition & 0 deletions .prettierrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ module.exports = {
singleQuote: true,
jsxSingleQuote: true,
tabWidth: 2,
printWidth: 150,
semi: true,
};
181 changes: 157 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,27 @@

</div>

Performer providing API for debounce, throttle and deduplication functions.
Performer providing API for debounce, throttle, deduplication and limiting functions.

**Contents:**

- [Installation](#installation)
- [API](#api)
- [Constructor](#constructor)
- [Parameters](#parameters)
- [Example](#example)
- [debounce](#debounce)
- [Parameters](#parameters-1)
- [Example](#example-1)
- [throttle](#throttle)
- [Parameters](#parameters-2)
- [Example](#example-2)
- [deduplicate](#deduplicate)
- [Parameters](#parameters-3)
- [Example](#example-3)
- [limit](#limit)
- [Parameters](#parameters-4)
- [Example](#example-4)

## Installation

Expand All @@ -25,29 +45,32 @@ yarn add function-performer

## API

### constructor
### Constructor

Type: `new (config?: PerformerConfig): Performer`

#### Options
#### Parameters

- `config` — Optional parameter providing the performer configuration.
- `debounce` - An optional property that provides a debounce configuration.
- `interval` - The time in milliseconds during which the target function execution will be discarded. _(default value is `0`)_
- `throttle` - An optional property that provides a throttle configuration.
- `interval` - The time in milliseconds during which the target function execution will be blocked. _(default value is `0`)_
- `deduplication` - An optional property that provides a deduplication configuration.
- `deduplicate` - An optional property that provides a deduplication configuration.
- `interval` - The time in milliseconds during which duplicate detection will occur after calling the target function. _(default value is `0`)_
- `limit` - An optional property that provides a limitation configuration.
- `max` - Maximum number of function calls. _(default value is `Infinity`)_

#### Example

```js
import { Performer } from 'function-performer';

const performer = new Performer({
debounce: { interval: 500 },
throttle: { interval: 1000 },
debounce: { interval: 100 },
throttle: { interval: 100 },
deduplication: { interval: 100 },
limit: { max: 5 },
});
```

Expand All @@ -67,9 +90,7 @@ Discards execution of operations performed within the specified interval.
```js
import { Performer } from 'function-performer';

const performer = new Performer({
debounce: { interval: 1000 },
});
const performer = new Performer({ debounce: { interval: 100 } });

const func = (arg: number) => {
console.log(arg);
Expand All @@ -84,6 +105,28 @@ setTimeout(() => {
}, 2000);
```

To set a configuration for specific cases, pass it to the `debounce.with` function:

```js
import { Performer } from 'function-performer';

const performer = new Performer();

const debounce = performer.debounce.with({ interval: 100 });

const func = (arg: number) => {
console.log(arg);
};

debounce(func, 1); // will be discarded
debounce(func, 2); // will be discarded
debounce(func, 3); // logs `3`

setTimeout(() => {
debounce(func, 4); // logs `4`
}, 2000);
```

### throttle

Type: `(func: ThrottledFunction, ...args: unknown[]) => void`
Expand All @@ -100,27 +143,50 @@ Blocks execution of operations performed within the specified interval.
```js
import { Performer } from 'function-performer';

const performer = new Performer({
// Will only allow one call every 100 milliseconds
throttle: { interval: 100 },
});
const performer = new Performer({ throttle: { interval: 100 } });

const func = (arg: number) => {
const func = (arg: string) => {
console.log(arg);
};

let time = 0;

// Will be called every 10ms
const interval = setInterval(() => {
if(time === 1000) {
if(time < 1000) {
performer.throttle(func, `${time}ms`); // logs `0ms`, `100ms`, `200ms`, etc.
} else {
clearInterval(interval);
return;
}

performer.throttle(func, time); // logs `0`, `100`, `200`, `300`, …, `900`

time += 10;
}, 10);
```

To set a configuration for specific cases, pass it to the `throttle.with` function:

```js
import { Performer } from 'function-performer';

const performer = new Performer();

const throttle = performer.throttle.with({ interval: 100 });

const func = (arg: string) => {
console.log(arg);
};

let time = 0;

// Will be called every 10 milliseconds
// Will be called every 10ms
const interval = setInterval(() => {
if(time < 1000) {
throttle(func, `${time}ms`); // logs `0ms`, `100ms`, `200ms`, etc.
} else {
clearInterval(interval);
}

time += 10;
}, 10);
```

Expand All @@ -140,9 +206,7 @@ Detects duplicate function calls and executes the function only once during the
```js
import { Performer } from 'function-performer';

const performer = new Performer({
deduplication: { interval: 100 },
});
const performer = new Performer({ deduplicate: { interval: 100 } });

const func1 = (count: number, arg: number) => {
console.log({ count, arg });
Expand All @@ -155,10 +219,79 @@ const func2 = (count: number, arg: object) => {
performer.deduplicate(func1, 1); // will be blocked
performer.deduplicate(func1, 1); // logs `{ count: 2, arg: 1 }`
performer.deduplicate(func2, { foo: { bar: 'baz' } }); // will be blocked
performer.deduplicate(func2, { foo: { bar: 'baz' } }); // will be blocked
performer.deduplicate(func2, { foo: { bar: 'baz' } }); // logs `{ count: 3, arg: { foo: { bar: 'baz' } } }`
performer.deduplicate(func2, { foo: { bar: 'baz' } }); // logs `{ count: 2, arg: { foo: { bar: 'baz' } } }`
performer.deduplicate(func2, { foo: { bar: 'qux' } }); // logs `{ count: 1, arg: { foo: { bar: 'qux' } } }`

setTimeout(() => {
performer.deduplicate(func2, { foo: { bar: 'baz' } }); // logs `{ count: 1, arg: { foo: { bar: 'baz' } } }`
}, 1000);
```

To set a configuration for specific cases, pass it to the `deduplicate.with` function:

```js
import { Performer } from 'function-performer';

const performer = new Performer();

const deduplicate = performer.deduplicate.with({ interval: 200 });

const func = (count: number, arg: number) => {
console.log({ count, arg });
};

deduplicate(func, 1); // will be blocked
deduplicate(func, 1); // logs `{ count: 2, arg: 1 }`
```

### limit

Type: `(func: LimitedFunction, ...args: unknown[]) => void`

Limits the maximum number of function calls.

#### Parameters

- `func` — A function whose number of calls will be limited.
- `...args` — A set of parameters for the function being performed.

#### Example

```js
import { Performer } from 'function-performer';

const performer = new Performer({ limit: { max: 3 } });

const func = (arg: number) => {
console.log(arg);
};

performer.limit(func, 1); // logs `1`
performer.limit(func, 2); // logs `2`
performer.limit(func, 3); // logs `3`
performer.limit(func, 4); // will be blocked
performer.limit(func, 5); // will be blocked
```

To set a configuration for specific cases, pass it to the `limit.with` function:

```js
import { Performer } from 'function-performer';

const performer = new Performer();

const once = performer.limit.with({ max: 1 });
const twice = performer.limit.with({ max: 2 });

const func = (arg: number) => {
console.log(arg);
};

once(func, 1); // logs `1`
once(func, 2); // will be blocked
once(func, 3); // will be blocked

twice(func, 1); // logs `1`
twice(func, 2); // logs `2`
twice(func, 3); // will be blocked
```
19 changes: 1 addition & 18 deletions commitlint.config.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,6 @@
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
[
'feat',
'fix',
'docs',
'chore',
'style',
'refactor',
'ci',
'test',
'perf',
'revert',
'build',
'lint',
],
],
'type-enum': [2, 'always', ['feat', 'fix', 'docs', 'chore', 'style', 'refactor', 'ci', 'test', 'perf', 'revert', 'build', 'lint']],
},
};
13 changes: 13 additions & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { type Config } from 'jest';

const config: Config = {
clearMocks: true,
collectCoverage: true,
collectCoverageFrom: ['src/**/*.{js,ts}', '!**/*.d.ts', '!**/node_modules/**'],
coverageDirectory: 'coverage',
preset: 'ts-jest',
testEnvironment: 'node',
};

// eslint-disable-next-line no-restricted-exports
export default config;
Loading