diff --git a/.editorconfig b/.editorconfig index 98a761d..1c6314a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,6 +7,6 @@ charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true -[{package.json,*.yml}] +[*.yml] indent_style = space indent_size = 2 diff --git a/.gitattributes b/.gitattributes index 391f0a4..6313b56 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1 @@ -* text=auto -*.js text eol=lf +* text=auto eol=lf diff --git a/.gitignore b/.gitignore index 3c3629e..239ecff 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules +yarn.lock diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..43c97e7 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/.travis.yml b/.travis.yml index 97519af..2ae9d62 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ language: node_js node_js: + - '10' + - '8' - '6' - - '4' diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..c5fd502 --- /dev/null +++ b/index.d.ts @@ -0,0 +1,21 @@ +export interface Options { + /** + * Call the `fn` on the [leading edge of the timeout](https://css-tricks.com/debouncing-throttling-explained-examples/#article-header-id-1). Meaning immediately, instead of waiting for `wait` milliseconds. + * + * @default false + */ + readonly leading?: boolean; +} + +/** + * [Debounce](https://css-tricks.com/debouncing-throttling-explained-examples/) promise-returning & async functions. + * + * @param fn - Promise-returning/async function to debounce. + * @param wait - Milliseconds to wait before calling `fn`. + * @returns Returns a function that delays calling `fn` until after `wait` milliseconds have elapsed since the last time it was called. + */ +export default function pDebounce( + fn: (...arguments: ArgumentsType) => PromiseLike | ReturnType, + wait: number, + options?: Options +): (...arguments: ArgumentsType) => Promise; diff --git a/index.js b/index.js index f609bbc..0f20230 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,6 @@ 'use strict'; -module.exports = (fn, wait, opts) => { + +const pDebounce = (fn, wait, opts) => { if (!Number.isFinite(wait)) { throw new TypeError('Expected `wait` to be a finite number'); } @@ -10,9 +11,8 @@ module.exports = (fn, wait, opts) => { let timer; let resolveList = []; - return function () { + return function (...args) { const ctx = this; - const args = arguments; return new Promise(resolve => { const runImmediately = opts.leading && !timer; @@ -40,3 +40,6 @@ module.exports = (fn, wait, opts) => { }); }; }; + +module.exports = pDebounce; +module.exports.default = pDebounce; diff --git a/index.test-d.ts b/index.test-d.ts new file mode 100644 index 0000000..8d3c9f7 --- /dev/null +++ b/index.test-d.ts @@ -0,0 +1,9 @@ +import {expectType} from 'tsd-check'; +import pDebounce from '.'; + +const expensiveCall = (input: number) => Promise.resolve(input); + +expectType<(input: number) => Promise>(pDebounce(expensiveCall, 200)); +expectType<(input: number) => Promise>( + pDebounce(expensiveCall, 200, {leading: true}) +); diff --git a/package.json b/package.json index 7a95729..41d410e 100644 --- a/package.json +++ b/package.json @@ -1,52 +1,54 @@ { - "name": "p-debounce", - "version": "1.0.0", - "description": "Debounce promise-returning & async functions", - "license": "MIT", - "repository": "sindresorhus/p-debounce", - "author": { - "name": "Sindre Sorhus", - "email": "sindresorhus@gmail.com", - "url": "sindresorhus.com" - }, - "engines": { - "node": ">=4" - }, - "scripts": { - "test": "xo && ava" - }, - "files": [ - "index.js" - ], - "keywords": [ - "promise", - "debounce", - "debounced", - "limit", - "limited", - "concurrency", - "throttle", - "throat", - "limited", - "interval", - "rate", - "batch", - "ratelimit", - "task", - "queue", - "async", - "await", - "promises", - "bluebird" - ], - "devDependencies": { - "ava": "*", - "delay": "^1.3.1", - "in-range": "^1.0.0", - "time-span": "^1.0.0", - "xo": "*" - }, - "xo": { - "esnext": true - } + "name": "p-debounce", + "version": "1.0.0", + "description": "Debounce promise-returning & async functions", + "license": "MIT", + "repository": "sindresorhus/p-debounce", + "author": { + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", + "url": "sindresorhus.com" + }, + "engines": { + "node": ">=6" + }, + "scripts": { + "test": "xo && ava && tsd-check" + }, + "files": [ + "index.js", + "index.d.ts" + ], + "keywords": [ + "promise", + "debounce", + "debounced", + "limit", + "limited", + "concurrency", + "throttle", + "throat", + "limited", + "interval", + "rate", + "batch", + "ratelimit", + "task", + "queue", + "async", + "await", + "promises", + "bluebird" + ], + "devDependencies": { + "ava": "^1.3.1", + "delay": "^4.1.0", + "in-range": "^1.0.0", + "time-span": "^2.0.0", + "tsd-check": "^0.3.0", + "xo": "^0.24.0" + }, + "xo": { + "esnext": true + } } diff --git a/readme.md b/readme.md index 8398963..8c121a6 100644 --- a/readme.md +++ b/readme.md @@ -38,7 +38,7 @@ Returns a function that delays calling `fn` until after `wait` milliseconds have Type: `Function` -Promise-returning/async function. +Promise-returning/async function to debounce. #### wait diff --git a/test.js b/test.js index 21ac528..d9d0d17 100644 --- a/test.js +++ b/test.js @@ -2,12 +2,12 @@ import test from 'ava'; import delay from 'delay'; import inRange from 'in-range'; import timeSpan from 'time-span'; -import m from './'; +import pDebounce from '.'; const fixture = Symbol('fixture'); test('single call', async t => { - const debounced = m(async val => val, 100); + const debounced = pDebounce(async val => val, 100); t.is(await debounced(fixture), fixture); }); @@ -15,7 +15,7 @@ test('multiple calls', async t => { let count = 0; const end = timeSpan(); - const debounced = m(async val => { + const debounced = pDebounce(async val => { count++; await delay(50); return val; @@ -34,7 +34,7 @@ test('multiple calls', async t => { test('leading option', async t => { let count = 0; - const debounced = m(async val => { + const debounced = pDebounce(async val => { count++; await delay(50); return val; @@ -53,7 +53,7 @@ test('leading option', async t => { test('leading option - does not call input function after timeout', async t => { let count = 0; - const debounced = m(async () => { + const debounced = pDebounce(async () => { count++; }, 100, {leading: true});