
Research
Two Malicious Rust Crates Impersonate Popular Logger to Steal Wallet Keys
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.
@danielhaim/modulator
Advanced tools
An advanced debouncing utility designed to optimize high-frequency events in web applications, such as scroll, resize, and input.
Event Modulator 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.
By incorporating a cache system for debounced function call results, Event 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 Event Modulator a superior choice for debouncing solutions in web applications.
You can install this module via npm:
$ npm i @danielhaim/modulator
If you prefer to use Event Modulator directly in your browser without installing the package, you can import it via a CDN like esm.sh. Simply add the following line to your HTML file or JavaScript module to start using it:
import { modulate } from "https://esm.sh/@danielhaim/modulator";
modulate(func, wait, immediateopt, contextopt, maxCacheSizeopt, maxWaitopt) → {function}
Creates 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.
Name | Type | Attributes | Default | Description |
---|---|---|---|---|
func | function | The function to debounce. | ||
wait | number | The debouncing wait time in milliseconds. | ||
immediate | boolean | <optional> | false | Flag to determine if the function should be executed immediately. |
context | Object | <optional> | null | The context in which the function should be executed. |
maxCacheSize | number | <optional> | 100 | The maximum cache size for storing results. |
maxWait | number | null | <optional> | null |
Once you create a debounced function using modulate
, it comes with additional methods that enhance its capabilities:
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.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.These methods provide greater control and flexibility in managing the debounced function, allowing for more sophisticated usage patterns in your applications.
The package can be imported and used in both Node.js and browser environments using the following syntax:
<script src="./path/to/modulator.amd.js"></script>
<script>
window.modulate = modulate;
const debouncedFunc = modulate(originalFunc, 1000);
</script>
In 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).
import modulate from "path/to/modulator.js";
// Debounce the function to be called only once per 100ms
const debouncedFunction = modulate(myFunction, 100);
// Call the debounced function on high-frequency events
element.addEventListener('mousemove', debouncedFunction);
const originalFunc = () => {
console.log('Original function called');
};
const debouncedFunc = modulate(originalFunc, 1000);
// Call the debounced function multiple times
debouncedFunc();
debouncedFunc();
debouncedFunc();
debouncedFunc();
debouncedFunc();
function handleResize(event) {
// Do something on resize
}
const debouncedHandleResize = modulate(handleResize, 100);
window.addEventListener('resize', debouncedHandleResize);
function handleSubmit(event) {
event.preventDefault();
// Make API request to submit form data
}
const debouncedHandleSubmit = modulate(handleSubmit, 1000, true);
document.querySelector('#my-form').addEventListener('submit', debouncedHandleSubmit);
function handleSearch(query) {
// Make API request and display results
}
const debouncedHandleSearch = modulate(handleSearch, 500);
document.querySelector('#search-input').addEventListener('input', (event) => {
debouncedHandleSearch(event.target.value);
});
function handleMouseover(event) {
// Display tooltip or other information
}
const debouncedHandleMouseover = modulate(handleMouseover, 250);
document.querySelector('#my-element').addEventListener('mouseover', debouncedHandleMouseover);
function handleResize(event) {
// do something on resize
}
const debouncedHandleResize = modulate(handleResize, 100, false, null, 10, 500);
window.addEventListener('resize', debouncedHandleResize);
function handleSubmit(event) {
event.preventDefault();
// make API request to submit form data
}
const debouncedHandleSubmit = modulate(handleSubmit, 1000, true);
document.querySelector('#my-form').addEventListener('submit', debouncedHandleSubmit);
function handleSearch(query) {
// make API request and display results
}
const debouncedHandleSearch = modulate(handleSearch, 500);
document.querySelector('#search-input').addEventListener('input', (event) => {
debouncedHandleSearch(event.target.value);
});
function handleMouseover(event) {
// display tooltip or other information
}
const debouncedHandleMouseover = modulate(handleMouseover, 250);
document.querySelector('#my-element').addEventListener('mouseover', debouncedHandleMouseover);
// Example function to fetch data
function fetchData(query) {
console.log(`Fetching data for query: ${query}`);
// Perform an operation, such as fetching from a server
return Promise.resolve(`Data for "${query}"`);
}
// Debounced version of fetchData with cache size of 2
const debouncedFetchData = modulate(fetchData, 500, false, null, 2);
// Call debouncedFetchData multiple times with the same query
debouncedFetchData('apple');
debouncedFetchData('apple');
debouncedFetchData('banana');
// Only the last call will invoke the original function after 500ms
setTimeout(() => {
debouncedFetchData('apple').then(console.log);
debouncedFetchData('banana').then(console.log);
}, 1000);
In 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.
// Define a simple function that adds two numbers
const originalFunc = (x, y) => x + y;
// Create a debounced version of the original function with a 1000ms wait time
const debouncedFunc = modulate(originalFunc, 1000);
// Call the debounced function multiple times within a short interval
const results = [];
for (let i = 0; i < 3; i++) {
results.push(debouncedFunc(1, 2)); // Each call returns a promise
}
// After the debounce interval, check the results
setTimeout(() => {
// Use Promise.all to wait for all debounced function calls to resolve
Promise.all(results).then(values => {
console.log('Results of each debounced call:', values); // Expect multiple [3]
console.log('Result from the debounced function\'s last execution:', debouncedFunc.result()); // Expect [3]
});
}, 2000);
Here'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.
import { modulate } from '../path/to/modulator.js';
// Example function to fetch data
function fetchData(query) {
console.log(`Fetching data for query: ${query}`);
// Perform expensive operation, such as fetching from a server
return Promise.resolve(`Data for "${query}"`);
}
// Debounced version of fetchData with cache size of 2
const debouncedFetchData = modulate(fetchData, 500, false, null, 2);
// Call debouncedFetchData multiple times with same query
debouncedFetchData('apple');
debouncedFetchData('apple');
debouncedFetchData('apple');
debouncedFetchData('banana');
debouncedFetchData('banana');
// Only the last 2 calls will invoke the original function after 1 second
setTimeout(() => {
debouncedFetchData('apple');
debouncedFetchData('banana');
}, 1000);
The 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.
In 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.
// Create a new Map object to store the cache
const cache = new Map();
// Memoize function takes in a function as an argument
const memoize = func => {
// Return a new function that takes any number of arguments
return function (...args) {
// Convert the arguments to a string to be used as a cache key
const key = JSON.stringify(args);
// Check if the result for the given arguments has already been cached
if (cache.has(key)) {
// If so, return the cached result
return cache.get(key);
}
// Otherwise, call the original function with the given arguments
const result = func(...args);
// Cache the result and return it
cache.set(key, result);
return result;
};
};
// Example function to be memoized
const originalFunc = x => x + 1;
// Memoized version of the function
const memoizedFunc = memoize(originalFunc);
// Call the memoized function three times with the same argument
const result1 = memoizedFunc(1);
const result2 = memoizedFunc(1);
const result3 = memoizedFunc(1);
Test Errors
✓ Should throw an error if the first parameter is not a function (3 ms)
✓ Should throw an error if the second parameter is not a number (1 ms)
✓ Should throw an error if the third parameter is not a boolean
✓ Should throw an error if the fifth parameter is not a number (1 ms)
✓ Should throw an error if the sixth parameter is not a number or null
✓ Should throw an error if the sixth parameter is less than the second parameter (1 ms)
Test Parameters
✓ Should debounce the original function
✓ Should delay execution by maxWait time (3 ms)
✓ Should cache results for the same arguments (1 ms)
✓ Should debounce a function and return a debounced function
✓ Should debounce and cache the results of the original function
Test EventListeners
✓ Should trigger mouseover event
✓ Should trigger window resize event (1 ms)
If you encounter any bugs while using Modulator, please report them to the GitHub issue tracker. When submitting a bug report, please include as much information as possible.
FAQs
An advanced debouncing utility designed to optimize high-frequency events in web applications, such as scroll, resize, and input.
We found that @danielhaim/modulator demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.
Research
A malicious package uses a QR code as steganography in an innovative technique.
Research
/Security News
Socket identified 80 fake candidates targeting engineering roles, including suspected North Korean operators, exposing the new reality of hiring as a security function.