Reputation: 311
I have a JavaScript function which actually ends up making a server-side call. I want to limit the rate at which this function can be called.
What is an easy way I can limit how fast my javascript function will get called by say 200-500 milliseconds or so? Should I use a javascript timer control?
Upvotes: 31
Views: 28156
Reputation: 872
I would suggest Pat Migliaccio solution found here
function limiter(fn, wait){
let isCalled = false,
calls = [];
let caller = function(){
if (calls.length && !isCalled){
isCalled = true;
calls.shift().call();
setTimeout(function(){
isCalled = false;
caller();
}, wait);
}
};
return function(){
calls.push(fn.bind(this, ...arguments));
caller();
};
}
You can easily test it by creating a loop:
const logMessageLimited = limiter(msg => { console.log(msg); }, 1000);
for (let i = 0; i < 10; i++){
logMessageLimited(`[Message Log] Action (${i}) rate limited.`);
}
Upvotes: 0
Reputation: 3756
It depends on what you want to do with subsequent calls, where you wanna run it etc.
Also serverside throttler like ratelimiter (async-ratelimiter), node-rate-limiter
Upvotes: 1
Reputation: 3432
If your problem involves too much work being created, use a queue:
const work_queue = [];
function queue(message) {
work_queue.push(message)
}
function run() {
const work = work_queue.shift();
if (work !== undefined) {
scan_one(work);
}
}
setInterval(run, 15);
If you problem involves a function being called too often:
let last = +new Date();
function run() {
const now = +new Date();
if (now - last > 5000) { // 5 seconds
last = now;
run_once();
}
}
Upvotes: 7
Reputation: 25172
Libraries like bottleneck and node-rate-limiter pretty much cover all use cases.
Upvotes: 9
Reputation: 5899
It kind of depends what functionality you want. Here is a link to a page that has 2 great functions: https://remysharp.com/2010/07/21/throttling-function-calls
throttle: process first call, then throttle next calls based on a threshhold (first and last call will be processed, but only a couple calls in between)
debounce: don't process any calls until function hasn't been called for a delay (only 1 will be called after a call and quite period)
Upvotes: 1
Reputation: 1
You can use debounce function
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this,
args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
var logging = debounce(function(){
alert("Heavy task");
}, 5000);
setTimeout(logging, 100);//callback executed after 5 seconds
More information on how debounce function works here http://qnimate.com/javascript-limit-function-call-rate/
Upvotes: -1
Reputation: 7653
You can also use the SugarJS function "throttle":
http://sugarjs.com/api/Function/throttle
Upvotes: 0
Reputation: 8211
First you need to establish if you want to rate limit in that you disregard all function calls that are made during the period when you are waiting, or whether you want to simply queue up requests so that you ensure you never make more than X requests per second.
If you want the former solution (disregard new functional calls), then you should look at http://documentcloud.github.com/underscore/#throttle
If you want to rate limit so that you never call your function more than X times per second, but don't lose those function calls altogether, then you need a wholly different solution.
I have written an underscore extension at https://gist.github.com/1084831 You can see a working example at http://jsbin.com/upadif/8/edit#preview
Upvotes: 5
Reputation: 7405
fooCanBeCalled = true;
function foo(){
if(!fooCanBeCalled) return;
//Whatever you want to do
fooCanBeCalled = false;
setTimeout(function(){
{
fooCanBecalled = true;
}
, delayInMilliseconds);
}
Upvotes: -3
Reputation:
This will not allow the function to run if less than 500 milliseconds have passed since the last call.
(function(window, undefined){
var canCall = true;
window.funcName = function(){
if (!canCall)
return;
//Your function
canCall = false;
setTimeout(function(){
canCall = true;
}, 500);
}
})(window);
Upvotes: 4
Reputation: 70011
You can create a flag that is raised when the function is called and start a timer and if this flag is raised then you can not call the function, then after a certain time, the timer is called and he turns off the flag, allowing you to call the function again.
The flag can be anything, like a bool or something.
Upvotes: 2