Skip to content

Commit 6492d81

Browse files
authored
Improve $.debounce(function, delay) method and add $.throttle(function, wait) method
.
1 parent 94d6622 commit 6492d81

File tree

2 files changed

+76
-9
lines changed

2 files changed

+76
-9
lines changed

src/main/java/com/github/underscore/$.java

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1324,11 +1324,44 @@ public static <T> java.util.concurrent.ScheduledFuture<T> defer(final Function<T
13241324
return delay(function, 0);
13251325
}
13261326

1327+
public static <T> Function<T> throttle(final Function<T> function, final int waitMilliseconds) {
1328+
class ThrottleFunction<T> implements Function<T> {
1329+
private final Function<T> localFunction;
1330+
private long previous;
1331+
private java.util.concurrent.ScheduledFuture<T> timeout;
1332+
1333+
ThrottleFunction(final Function<T> function) {
1334+
this.localFunction = function;
1335+
}
1336+
1337+
@Override
1338+
public T apply() {
1339+
final long now = now();
1340+
if (previous == 0L) {
1341+
previous = now;
1342+
}
1343+
final long remaining = waitMilliseconds - (now - previous);
1344+
if (remaining <= 0) {
1345+
clearTimeout(timeout);
1346+
previous = now;
1347+
localFunction.apply();
1348+
} else {
1349+
timeout = delay(localFunction, waitMilliseconds);
1350+
}
1351+
return null;
1352+
}
1353+
}
1354+
return new ThrottleFunction<T>(function);
1355+
}
1356+
13271357
public static <T> Function<T> debounce(final Function<T> function, final int delayMilliseconds) {
13281358
return new Function<T>() {
1359+
private java.util.concurrent.ScheduledFuture<T> timeout;
1360+
13291361
@Override
13301362
public T apply() {
1331-
delay(function, delayMilliseconds);
1363+
clearTimeout(timeout);
1364+
timeout = delay(function, delayMilliseconds);
13321365
return null;
13331366
}
13341367
};
@@ -1365,39 +1398,45 @@ public T apply(final T arg) {
13651398
}
13661399

13671400
public static <E> Function<E> after(final int count, final Function<E> function) {
1368-
class AfterFunction implements Function<E> {
1401+
class AfterFunction<E> implements Function<E> {
13691402
private final int count;
1403+
private final Function<E> localFunction;
13701404
private int index;
13711405
private E result;
1372-
public AfterFunction(final int count) {
1406+
1407+
AfterFunction(final int count, final Function<E> function) {
13731408
this.count = count;
1409+
this.localFunction = function;
13741410
}
13751411
public E apply() {
13761412
if (++index >= count) {
1377-
result = function.apply();
1413+
result = localFunction.apply();
13781414
}
13791415
return result;
13801416
}
13811417
}
1382-
return new AfterFunction(count);
1418+
return new AfterFunction<E>(count, function);
13831419
}
13841420

13851421
public static <E> Function<E> before(final int count, final Function<E> function) {
1386-
class BeforeFunction implements Function<E> {
1422+
class BeforeFunction<E> implements Function<E> {
13871423
private final int count;
1424+
private final Function<E> localFunction;
13881425
private int index;
13891426
private E result;
1390-
public BeforeFunction(final int count) {
1427+
1428+
BeforeFunction(final int count, final Function<E> function) {
13911429
this.count = count;
1430+
this.localFunction = function;
13921431
}
13931432
public E apply() {
13941433
if (++index <= count) {
1395-
result = function.apply();
1434+
result = localFunction.apply();
13961435
}
13971436
return result;
13981437
}
13991438
}
1400-
return new BeforeFunction(count);
1439+
return new BeforeFunction<E>(count, function);
14011440
}
14021441

14031442
public static <T> Function<T> once(final Function<T> function) {

src/test/java/com/github/underscore/FunctionsTest.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,34 @@ public Integer apply(final Integer n) {
9999
assertEquals(55, memoizeFunction.apply(10).intValue());
100100
}
101101

102+
/*
103+
var counter = 0;
104+
var incr = function(){ counter++; };
105+
var throttleIncr = _.throttle(incr, 32);
106+
throttleIncr(); throttleIncr();
107+
_.delay(throttleIncr, 16);
108+
_.delay(function(){ equal(counter, 1, 'incr was throttled'); }, 96);
109+
*/
110+
111+
@Test
112+
public void throttle() throws Exception {
113+
final Integer[] counter = new Integer[] {0};
114+
Function<Void> incr = new Function<Void>() { public Void apply() {
115+
counter[0]++; return null; } };
116+
Function<Void> throttleIncr = $.throttle(incr, 50);
117+
throttleIncr.apply();
118+
throttleIncr.apply();
119+
$.delay(throttleIncr, 16);
120+
$.delay(new Function<Void>() {
121+
public Void apply() {
122+
assertEquals("incr was throttled", 1, counter[0].intValue());
123+
return null;
124+
}
125+
}, 60);
126+
Thread.sleep(120);
127+
throttleIncr.apply();
128+
}
129+
102130
/*
103131
var counter = 0;
104132
var incr = function(){ counter++; };

0 commit comments

Comments
 (0)