UNPKG

async-wrappers

Version:

A set of wrapper functions to perform debouncing, throttling, retrying etc.

116 lines (99 loc) 2.82 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _callReduce = _interopRequireDefault(require("./callReduce")); var _deferred = _interopRequireDefault(require("./deferred")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Ensure multiple calls to a function will only execute it when it has been * inactive (no more calls) for a specified delay. * * Execution always happens asynchronously. * * If the delay is `0` execution will be scheduled to occur after the current * runtime event loop. * * The debounced function returns a promise that resolves to the return value * of `func`. * * By default the arguments to `func` are the latest arguments given to the * debounced function. For custom behaviour pass an `argumentsReducer` * function. * * @param fn The function to debounce * @param delay The number of milliseconds on inactivity before the function * will be executed. . * @return the debounced function * * @category Wrapper */ const debounce = (fn, delay = 50, options = {}) => { const { reducer, maxDelay = 0, maxCalls, onCancel } = options; let started = 0; let calls = 0; // Micro optimization if delay is zero defer will always force execution next tick so we can ignore maxDelay // as all calls this process tick will be handled next tick const afterReduce = delay > 0 && maxDelay > 0 ? () => { if (maxCalls) { calls++; if (calls >= maxCalls) { flush(); return; } } if (execute.delay < 0) { // execute is fresh reset started started = Date.now(); execute.defer(Math.min(delay, maxDelay)); } else { const elapsed = Date.now() - started; if (elapsed >= maxDelay) { // it's been too long force execution next tick execute.defer(0); } else { const wait = Math.min(delay, maxDelay - elapsed); execute.defer(wait); } } } : () => { if (maxCalls) { calls++; if (calls >= maxCalls) { flush(); return; } } execute.defer(delay); }; const [call, runner, reject] = (0, _callReduce.default)(fn, reducer, undefined, afterReduce); const execute = (0, _deferred.default)(() => { calls = 0; runner()(); }); const flush = () => { calls = 0; execute.cancel(); (0, _deferred.default)(runner()).defer(0); }; const cancel = reason => { calls = 0; execute.cancel(); if (onCancel) { onCancel(); } reject(reason ? reason : new Error('cancelled')); }; const debounced = call; debounced.cancel = cancel; debounced.flush = flush; return debounced; }; var _default = debounce; exports.default = _default;