limiter-component
Advanced tools
Comparing version 0.1.0 to 0.2.0
36
index.js
@@ -6,5 +6,8 @@ | ||
function limiter(interval) { | ||
function limiter(interval, penaltyInterval) { | ||
var queue = [], lastTrigger = 0, timer; | ||
var queue = [], | ||
lastTrigger = 0, | ||
penaltyCounter = 0, | ||
timer; | ||
@@ -19,7 +22,17 @@ function now() { | ||
function currentInterval() { | ||
return penaltyCounter > 0 ? penaltyInterval : interval; | ||
} | ||
function runNow(fn) { | ||
penaltyCounter = 0; | ||
fn(); | ||
lastTrigger = now(); | ||
} | ||
function deque() { | ||
timer = undefined; | ||
var fn = queue.shift(); | ||
fn(); | ||
lastTrigger = now(); | ||
if (since() >= currentInterval()) { | ||
runNow(queue.shift()); | ||
} | ||
schedule(); | ||
@@ -30,3 +43,3 @@ } | ||
if (!timer && queue.length) { | ||
timer = setTimeout(deque, interval - since()); | ||
timer = setTimeout(deque, currentInterval() - since()); | ||
} | ||
@@ -36,5 +49,4 @@ } | ||
function trigger(fn) { | ||
if (since() >= interval && !queue.length) { | ||
fn(); | ||
lastTrigger = now(); | ||
if (since() >= currentInterval() && !queue.length) { | ||
runNow(fn); | ||
} else { | ||
@@ -46,2 +58,6 @@ queue.push(fn); | ||
function penalty() { | ||
penaltyCounter += 1; | ||
} | ||
function cancel() { | ||
@@ -54,6 +70,8 @@ if (timer) { | ||
penaltyInterval = penaltyInterval || 5 * interval; | ||
return { | ||
trigger: trigger, | ||
penalty: penalty, | ||
cancel: cancel | ||
}; | ||
} |
{ | ||
"name": "limiter-component", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"description": "Limits the rate of function calls to one per period. It delays but does not throttle the calls.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -0,1 +1,2 @@ | ||
[![Build Status](https://secure.travis-ci.org/code42day/limiter.png)](http://travis-ci.org/code42day/limiter) | ||
@@ -35,2 +36,5 @@ # limiter | ||
l.trigger(doThis); | ||
l.trigger(function() { | ||
l.penalty(); // wait a bit longer next time | ||
}); | ||
l.trigger(doThat); | ||
@@ -41,5 +45,7 @@ ``` | ||
### limiter(interval) | ||
### limiter(interval, [penaltyInterval]) | ||
Create `limiter` with desired `interval` (in millis). | ||
Create `limiter` with desired `interval` (in millis). Optional `penaltyInterval` is used instead of | ||
`interval` if `limiter.penalty()` has been called at least once since last limited function has been | ||
triggered. | ||
@@ -51,2 +57,6 @@ ### trigger(fn) | ||
### penalty() | ||
Make limiter to use `penaltyInterval` before triggering next function. | ||
### cancel() | ||
@@ -53,0 +63,0 @@ |
@@ -7,3 +7,4 @@ var limiter = require('../index.js'); | ||
it('should call fn at most once per interval', function(done){ | ||
var l = limiter(200), | ||
var interval = 35, | ||
l = limiter(interval), | ||
results = []; | ||
@@ -22,8 +23,9 @@ | ||
results | ||
.map(function(item) { | ||
return item - results[0]; | ||
.map(function(item, i) { | ||
var prev = (i === 0) ? results[0] : results[i - 1]; | ||
return item - prev; | ||
}) | ||
.forEach(function(item, i) { | ||
if (i > 0) { | ||
assert.ok(item >= 200); | ||
assert.ok(item >= interval); | ||
} | ||
@@ -34,2 +36,70 @@ }); | ||
}); | ||
it('should delay calls on penalty', function(done) { | ||
var interval = 35, | ||
penaltyInterval = 150, | ||
l = limiter(interval, penaltyInterval), | ||
results = []; | ||
function push() { | ||
results.push(+(new Date)); | ||
if (results.length === 2) { | ||
l.penalty(); | ||
} | ||
} | ||
l.trigger(push); | ||
l.trigger(push); | ||
l.trigger(push); | ||
l.trigger(push); | ||
l.trigger(function() { | ||
assert.equal(results.length, 4); | ||
results | ||
.map(function(item, i) { | ||
var prev = (i === 0) ? results[0] : results[i - 1]; | ||
return item - prev; | ||
}) | ||
.forEach(function(item, i) { | ||
if (i === 0) { | ||
return; | ||
} | ||
if (i === 2) { | ||
assert.ok(item >= penaltyInterval); | ||
} else { | ||
assert.ok(item >= interval); | ||
assert.ok(item < penaltyInterval); | ||
} | ||
}); | ||
done(); | ||
}); | ||
}); | ||
it('delay works even when queue is empty', function(done) { | ||
var interval = 50, | ||
l = limiter(interval), | ||
time = Date.now(); | ||
l.trigger(function() { | ||
}); | ||
l.trigger(function() { | ||
var delay = Date.now() - time; | ||
assert.ok(delay >= interval); | ||
done(); | ||
}); | ||
}); | ||
it('penalty works even when queue is empty', function(done) { | ||
var interval = 50, | ||
l = limiter(interval), | ||
time = Date.now(); | ||
l.trigger(function() { | ||
l.penalty(); | ||
}); | ||
l.trigger(function() { | ||
var delay = Date.now() - time; | ||
assert.ok(delay >= 5 * interval); | ||
done(); | ||
}); | ||
}); | ||
}); |
6717
10
164
67