{"id":18455480,"url":"https://github.com/danielhaim1/modulator","last_synced_at":"2025-04-08T04:34:01.552Z","repository":{"id":149898432,"uuid":"622353846","full_name":"danielhaim1/Modulator","owner":"danielhaim1","description":"An advanced debouncing utility designed to optimize high-frequency events in web applications, such as scroll, resize, and input.","archived":false,"fork":false,"pushed_at":"2025-01-16T12:06:07.000Z","size":3047,"stargazers_count":3,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-02T18:53:09.433Z","etag":null,"topics":["debounce","helper","optimization","performance","throttle","utility"],"latest_commit_sha":null,"homepage":"https://danielhaim1.github.io/Modulator/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/danielhaim1.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-04-01T21:24:26.000Z","updated_at":"2025-01-16T12:06:08.000Z","dependencies_parsed_at":"2024-06-12T20:08:52.638Z","dependency_job_id":"784b0154-540d-47eb-bcab-3a3944fdc40b","html_url":"https://github.com/danielhaim1/Modulator","commit_stats":null,"previous_names":["danielhaim1/event-modulator","danielhaim1/modulator"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielhaim1%2FModulator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielhaim1%2FModulator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielhaim1%2FModulator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielhaim1%2FModulator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/danielhaim1","download_url":"https://codeload.github.com/danielhaim1/Modulator/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247779796,"owners_count":20994569,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["debounce","helper","optimization","performance","throttle","utility"],"created_at":"2024-11-06T08:08:09.386Z","updated_at":"2025-04-08T04:34:00.586Z","avatar_url":"https://github.com/danielhaim1.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"Modulator\n=========\n\n[![npm version](https://img.shields.io/npm/v/@danielhaim/modulator)](https://www.npmjs.com/package/@danielhaim/modulator)\n[![Downloads](https://img.shields.io/npm/dt/@danielhaim/modulator.svg)](https://www.npmjs.com/package/@danielhaim/modulator)\n![GitHub](https://img.shields.io/github/license/danielhaim1/modulator)\n\nModulator is an advanced debouncing utility designed to optimize high-frequency events in web applications, such as scroll, resize, and input. This standalone solution surpasses other debouncing functions like Lodash and Underscore in terms of performance and flexibility. Key features include parameter validation, cache, and result storage, control over cache size, a maximum wait time, and a Promise-based return.\n\nBy incorporating a cache system for debounced function call results, Modulator allows users to control the cache size through the maxCacheSize parameter, optimizing performance and memory usage. The Promise-based return simplifies the handling and tracking of function call outcomes. Additionally, the module includes a cancel method for aborting the debounced function execution when necessary and a result method for retrieving the result of the last execution. These features provide enhanced control and flexibility for developers, making Modulator a superior choice for debouncing solutions in web applications.\n\n## Demo ##\n\n\u003ca target=\"_blank\" href=\"https://danielhaim1.github.io/Modulator/\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/danielhaim1/Modulator/main/docs/assets/demo.png\" width=\"100%\" height=\"auto\" alt=\"Modulator Demo\"\u003e\u003c/a\u003e\n\nAPI Documentation\n-----------------\n\nTo initiate, install `Modulator` using NPM:\n\n```bash\nnpm i @danielhaim/modulator\n```\n\n### Module Example ###\n\n```js\nimport Modulator from \"./path/to/danielhaim/modulator\";\n// CDN → import Modulator from \"https://esm.sh/@danielhaim/modulator\"\n\nModulator.modulate(func, wait, immediateopt, contextopt, maxCacheSizeopt, maxWaitopt) → {function}\n```\n\n### `Modulator.modulate()` ###\n\nCreates a debounced function with a configurable cache and maximum wait time. The debounced function delays invoking `func` until after `wait` milliseconds have elapsed since the last time the debounced function was invoked. The function also caches its results based on the arguments passed. If `immediate` is true, it triggers the function on the leading edge, instead of the trailing.\n\n### Parameters ###\n\n|Name|Type|Attributes|Default|Description|\n|--- |--- |--- |--- |--- |\n|`func`|function|||The function to debounce.|\n|`wait`|number|||The debouncing wait time in milliseconds.|\n|`immediate`|boolean|`\u003coptional\u003e`|false|Flag to determine if the function should be executed immediately.|\n|`context`|Object|`\u003coptional\u003e`|null|The context in which the function should be executed.|\n|`maxCacheSize`|number|`\u003coptional\u003e`|100|The maximum cache size for storing results.|\n|`maxWait`|number|null|`\u003coptional\u003e`|null|The maximum wait time in milliseconds that the function can be delayed.|\n\n### Enhanced Functionality ###\n\nOnce you create a debounced function using `modulate`, it comes with additional methods that enhance its capabilities:\n\n- `debounced.cancel()`: Cancels the execution of the debounced function. This is useful if you need to prevent the function from being called if certain conditions are met.\n- `debounced.result()`: Returns an array of the results from all the invocations of the debounced function. It provides a way to access the outcomes of the function calls, especially useful when dealing with asynchronous operations.\n\nThese methods provide greater control and flexibility in managing the debounced function, allowing for more sophisticated usage patterns in your applications.\n\nExamples\n--------\n\nThe package can be imported and used in both Node.js and browser environments using the following syntax:\n\n```html\n\u003cscript src=\"./path/to/modulator.amd.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n  const debouncedFunc = Modulator.modulate(originalFunc, 1000);\n\u003c/script\u003e\n```\n\nIn the example Below, `debouncedFunc` is a debounced version of `originalFunc`. The function `originalFunc` will be invoked no more than once every 1000 milliseconds (1 second).\n\n```js\nimport Modulator from \"./path/to/danielhaim/modulator\";\n\n// Debounce the function to be called only once per 100ms\nconst debouncedFunction = Modulator.modulate(myFunction, 100);\n\n// Call the debounced function on high-frequency events\nelement.addEventListener('mousemove', debouncedFunction);\n\nconst originalFunc = () =\u003e {\n  console.log('Original function called');\n};\n\nconst debouncedFunc = Modulator.modulate(originalFunc, 1000);\n\n// Call the debounced function multiple times\ndebouncedFunc();\ndebouncedFunc();\ndebouncedFunc();\ndebouncedFunc();\ndebouncedFunc();\n```\n\n### Debouncing a resize event listener ###\n\n```js\nfunction handleResize(event) {\n  // Do something on resize\n}\n\nconst debouncedHandleResize = Modulator.modulate(handleResize, 100);\n\nwindow.addEventListener('resize', debouncedHandleResize);\n```\n\n### Debouncing a form submission ###\n\n```js\nfunction handleSubmit(event) {\n  event.preventDefault();\n  // Make API request to submit form data\n}\n\nconst debouncedHandleSubmit = Modulator.modulate(handleSubmit, 1000, true);\n\ndocument.querySelector('#my-form').addEventListener('submit', debouncedHandleSubmit);\n```\n\n### Debouncing a search function ###\n  \n```js\nfunction handleSearch(query) {\n  // Make API request and display results\n}\n\nconst debouncedHandleSearch = Modulator.modulate(handleSearch, 500);\n\ndocument.querySelector('#search-input').addEventListener('input', (event) =\u003e {\n  debouncedHandleSearch(event.target.value);\n});\n```\n\n### Debouncing a mouseover event listener ###\n\n```js\nfunction handleMouseover(event) {\n  // Display tooltip or other information\n}\n\nconst debouncedHandleMouseover = Modulator.modulate(handleMouseover, 250);\n\ndocument.querySelector('#my-element').addEventListener('mouseover', debouncedHandleMouseover);\n```\n\n### Debouncing a resize event listener with a maximum wait time ###\n\n```js\nfunction handleResize(event) {\n  // do something on resize\n}\n\nconst debouncedHandleResize = Modulator.modulate(handleResize, 100, false, null, 10, 500);\n\nwindow.addEventListener('resize', debouncedHandleResize);\n```\n\n### Debouncing a form submission ###\n\n```js\nfunction handleSubmit(event) {\n  event.preventDefault();\n  // make API request to submit form data\n}\n\nconst debouncedHandleSubmit = Modulator.modulate(handleSubmit, 1000, true);\n\ndocument.querySelector('#my-form').addEventListener('submit', debouncedHandleSubmit);\n```\n\n### Debouncing a search function ###\n\n```js\nfunction handleSearch(query) {\n  // make API request and display results\n}\n\nconst debouncedHandleSearch = Modulator.modulate(handleSearch, 500);\n\ndocument.querySelector('#search-input').addEventListener('input', (event) =\u003e {\n  debouncedHandleSearch(event.target.value);\n});\n```\n\n### Debouncing a mouseover event listener ###\n\n```js\nfunction handleMouseover(event) {\n  // display tooltip or other information\n}\n\nconst debouncedHandleMouseover = Modulator.modulate(handleMouseover, 250);\n\ndocument.querySelector('#my-element').addEventListener('mouseover', debouncedHandleMouseover);\n```\n\nAdvanced Examples\n-----------------\n\n### Debouncing a function with cache ###\n\n```js\n// Example function to fetch data\nfunction fetchData(query) {\n  console.log(`Fetching data for query: ${query}`);\n  // Perform an operation, such as fetching from a server\n  return Promise.resolve(`Data for \"${query}\"`);\n}\n\n// Debounced version of fetchData with cache size of 2\nconst debouncedFetchData = Modulator.modulate(fetchData, 500, false, null, 2);\n\n// Call debouncedFetchData multiple times with the same query\ndebouncedFetchData('apple');\ndebouncedFetchData('apple');\ndebouncedFetchData('banana');\n\n// Only the last call will invoke the original function after 500ms\nsetTimeout(() =\u003e {\n  debouncedFetchData('apple').then(console.log);\n  debouncedFetchData('banana').then(console.log);\n}, 1000);\n```\n\n### Debouncing a Function with Result Aggregation ###\n\nIn this example, `originalFunc` calculates the sum of two numbers. We debounce this function using `modulate`. Despite multiple calls to the debounced function with the same arguments within a short interval, it only executes once after the 1000ms wait time. The result method then retrieves the `result` of the debounced function's last execution, which is `[3]` in this case.\n\n```js\n// Define a simple function that adds two numbers\nconst originalFunc = (x, y) =\u003e x + y;\n\n// Create a debounced version of the original function with a 1000ms wait time\nconst debouncedFunc = Modulator.modulate(originalFunc, 1000);\n\n// Call the debounced function multiple times within a short interval\nconst results = [];\nfor (let i = 0; i \u003c 3; i++) {\n  results.push(debouncedFunc(1, 2)); // Each call returns a promise\n}\n\n// After the debounce interval, check the results\nsetTimeout(() =\u003e {\n  // Use Promise.all to wait for all debounced function calls to resolve\n  Promise.all(results).then(values =\u003e {\n    console.log('Results of each debounced call:', values); // Expect multiple [3]\n    console.log('Result from the debounced function\\'s last execution:', debouncedFunc.result()); // Expect [3]\n  });\n}, 2000);\n```\n\n### Debouncing a function with cache ###\n\nHere's an example of creating a debounced version of a function `fetchData` with a cache size of 2. The debounced function `debouncedFetchData` is called multiple times with the same query ('apple' and 'banana'). Still, the original part is only invoked for the last two calls (one for 'apple' and one for 'banana'). After 1 second, the function is called again for 'apple' and 'banana,' and the results are retrieved from the cache instead of invoking the original function.\n\n```js\nimport Modulator from \"@danielhaim/modulator\";\n\n// Example function to fetch data\nfunction fetchData(query) {\n  console.log(`Fetching data for query: ${query}`);\n  // Perform expensive operation, such as fetching from a server\n  return Promise.resolve(`Data for \"${query}\"`);\n}\n\n// Debounced version of fetchData with cache size of 2\nconst debouncedFetchData = Modulator.modulate(fetchData, 500, false, null, 2);\n\n// Call debouncedFetchData multiple times with same query\ndebouncedFetchData('apple');\ndebouncedFetchData('apple');\ndebouncedFetchData('apple');\ndebouncedFetchData('banana');\ndebouncedFetchData('banana');\n\n// Only the last 2 calls will invoke the original function after 1 second\nsetTimeout(() =\u003e {\n  debouncedFetchData('apple');\n  debouncedFetchData('banana');\n}, 1000);\n```\n\n#### maxCacheSize Parameter ###\n\nThe modulate function includes a `maxCacheSize` parameter that allows you to control the cache size of the debounced function. This parameter specifies the maximum number of function results that should be cached. Once the cache size is reached, the oldest result will be removed to accommodate the new result. If `maxCacheSize` is set to `null` or `undefined,` the cache will have unlimited size.\n\n#### Caching results ###\n\nIn this example, the `memoize` function creates a cached version of a function to return the same result for the same arguments, improving performance by avoiding unnecessary function calls.\n\n```js\n// Create a new Map object to store the cache\nconst cache = new Map();\n\n// Memoize function takes in a function as an argument\nconst memoize = func =\u003e {\n  // Return a new function that takes any number of arguments\n  return function (...args) {\n    // Convert the arguments to a string to be used as a cache key\n    const key = JSON.stringify(args);\n    // Check if the result for the given arguments has already been cached\n    if (cache.has(key)) {\n      // If so, return the cached result\n      return cache.get(key);\n    }\n    // Otherwise, call the original function with the given arguments\n    const result = func(...args);\n    // Cache the result and return it\n    cache.set(key, result);\n    return result;\n  };\n};\n\n// Example function to be memoized\nconst originalFunc = x =\u003e x + 1;\n// Memoized version of the function\nconst memoizedFunc = memoize(originalFunc);\n// Call the memoized function three times with the same argument\nconst result1 = memoizedFunc(1);\nconst result2 = memoizedFunc(1);\nconst result3 = memoizedFunc(1);\n```\n\nTests\n-----\n\n```bash\nTest Errors\n✓ Should throw an error if the first parameter is not a function (2 ms)\n✓ Should throw an error if the second parameter is not a number (1 ms)\n✓ Should throw an error if the third parameter is not a boolean\n✓ Should throw an error if the fifth parameter is not a number (1 ms)\n✓ Should throw an error if the sixth parameter is not a number or null (1 ms)\n✓ Should throw an error if the sixth parameter is less than the second parameter\n\nTest Parameters\n✓ Should debounce the original function (1 ms)\n✓ Should delay execution by maxWait time (1 ms)\n✓ Should cache results for the same arguments (1 ms)\n✓ Should debounce a function and return a debounced function\n✓ Should debounce and cache the results of the original function\n\nTest EventListeners\n✓ Should trigger mouseover event (1 ms)\n✓ Should trigger window resize event\n```\n\nResources\n---------\n\n- [The Debouncing and Throttling Explained article on the CSS-Tricks website](https://css-tricks.com/debouncing-throttling-explained-examples/)\n- [The Underscore.js documentation on the debounce function](https://underscorejs.org/#debounce)\n- [The Lodash documentation on the debounce function](https://lodash.com/docs/4.17.15#debounce)\n\nReport Bugs\n-----------\n\nIf you encounter any bugs while using Modulator, please report them to the GitHub issue tracker.\nWhen submitting a bug report, please include as much information as possible.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanielhaim1%2Fmodulator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdanielhaim1%2Fmodulator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanielhaim1%2Fmodulator/lists"}