1.0.5 • Published 5 years ago

proxy-throttle-debounce v1.0.5

Weekly downloads
7
License
ISC
Repository
github
Last release
5 years ago

npm version dependencies Status devDependencies Status

proxy-throttle-debounce

proxy-throttle-debounce is a debouncing and throttling middleware that can be used for delaying, ignoring method calls on a JavaScript object, or an new instance of a class or a function. It acts as an abstraction layer between your code and the throttling logic.

Table of contents

Prequisites

Installing

npm install proxy-throttle-debounce

Example:

Find something you want to throttle, for example the methods of this object:

const myObject = {
	methodToDebounce: () => console.log("I'm important!"),
	methodToThrottle: () => console.log("Hello there!"),
	methodToDelay: () => console.log("Not so fast!"),
	promiseToDebounce: () => Promise.resolve("Never let me down!")
}

Initialization:

const Proxifier = require('proxy-throttle-debounce')

Create a methodMap. It should be a map of the methods of the object that you want to throttle or debounce.

const methodMap = [
	{name:'methodToDebounce', cooldownAction:'debounce', cooldownTime:1000},
	{name:'methodToThrottle', cooldownAction:'throttle', cooldownTime:1500},
	{name:'methodToDelay', cooldownAction:'delay', cooldownTime:2000},
	{name:'promiseToDebounce', cooldownAction:'debounce', cooldownTime:2000, promise: true},
]

The properties of an object in the methodmap should be:

  • name: the name of the method
  • cooldownAction: the action to perform when the method is called
    • debounce: waits until the cooldown period passes, postpones the execution if the method is called again during the cooldown period
    • throttle: calls the method, but ignores method calls until the cooldown period passes
    • delay: delays repeated method calls
  • cooldownTime: the cooldown period in milliseconds
  • promise: optional, should be true if the method returns a promise
  • skiplog: optional, by default the proxifier logs the method name before execution, set the skiplog to true to prevent this

Create a new instance of the Proxifier, pass a methodMap to the constructor:

const proxifier = new Proxifier(methodMap)

Create a proxified copy of the original object:

const testObject = proxifier.wrap(myObject)

Spam the methods:

  • debounce:
testObject.methodToDebounce()
  • throttle:
testObject.methodToThrottle()
  • delay:
testObject.methodToDelay()
  • debounced promise:
testObject.promiseToDebounce().then(console.log)

Documentation

methods

constructor(methodMap, label)

  • methodMap - Array. Configuration for the methods you want to throttle or debounce. The example section above details the properties the map elements should have.
  • label - String. This label is prepended to every log output. If you wish to not prepend the logs with a label, pass an empty string. Defaults to 'proxyObject'.

wrap(obj)

Returns a proxified copy of the object that was passed as the obj parameter. The object can be a JavaScript object or a new instance of a function or a class. It applies the throttling and debouncing rules defined in the methodMap. This method replaces the execution context of the throttled or debounced methods of the original object with the execution context of the proxified copy. See the reasoning behind this under the tips section. If you want to create a proxified copy while leaving the original object unmodified, use the wrap2 method.

wrap2(obj)

Returns a proxified copy without replacing the original object's execution context.

Tips

What can be throttled or debounced

Basically every method call can be throttled or debounced, but don't expect return values from a synchronous method. Example:

const Proxifier = require('proxy-throttle-debounce')

const obj = {}

//The return value of this method will be lost during debouncing
obj.multiply2 = function(number){
	console.log('log: multiplying', number)
	return number * 2
}
const rules = {name: 'multiply2', cooldownAction: 'debounce', cooldownTime: 2000, skiplog: true}
const proxifier = new Proxifier([rules])
const proxied = proxifier.wrap(obj)

let double2 = proxied.multiply2(2)
//2 seconds later:
//log: multiplying 2

console.log(double2) //undefined

How to overcome this issue? Use asynchronous functions (or callbacks).

const Proxifier = require('proxy-throttle-debounce')

const obj = {}

obj.multiply2 = function(number){	
	console.log('log: multiplying', number)
	return Promise.resolve(number * 2)
}
const rules = {name: 'multiply2', cooldownAction: 'debounce', cooldownTime: 2000, skiplog: true, promise: true}
const proxifier = new Proxifier([rules])
const proxied = proxifier.wrap(obj)

proxied.multiply2(2).then((result) => console.log('The result is:', result))
//2 seconds later:
//log: multiplying 2
//The result is: 4

A note on the testability of throttled or debounced method calls that returns promises

Design your test cases carefully for methods that return a promise, because if a method call needs throttling or debouncing, the promise will not resolve nor reject.

A note on the execution context

The proxifier replaces the original object's execution context (the object the this keyword points to) with the execution context of the proxified copy. This is needed because internal method calls, or event listener functions of an object wouldn't get throttled or debounced otherwise. Replacing the execution context makes the following example possible.

const Proxifier = require('proxy-throttle-debounce')

const obj = {}

obj.func1 = function(){
	//I'm calling func2
	this.func2("You are the best!")
}

obj.func2 = function(message){	
	console.log('Message from func1:', message)
}

//not applying throttling or debouncing logic, just logging the method calls
const rules = [{name:'func1'}, {name:'func2'}]

const proxifier = new Proxifier(rules, 'funcTest')
const proxied = proxifier.wrap(obj)

proxied.func1()
//funcTest func1
//funcTest func2
//Message from func1: You are the best!

Without replacing the execution context, the 'this' keyword inside proxied.func2 would refer to obj. The proxifier can't throttle obj, it can only throttle proxied which is the proxified copy of obj.

However if you create a proxified copy with the wrap2 method that does not replace the execution context and the output will be this:

const proxifier = new Proxifier(rules, 'funcTest')
const proxied = proxifier.wrap2(obj)
proxied.func1()
//funcTest func1
//Message from func1: You are the best!
1.0.5

5 years ago

1.0.4

5 years ago

1.0.3

5 years ago

1.0.2

5 years ago

1.0.1

5 years ago

1.0.0

6 years ago