Skip to content

Commit f1d11bb

Browse files
committed
avoid creating runloop for debounce and throttle
1 parent 43c153d commit f1d11bb

File tree

4 files changed

+44
-84
lines changed

4 files changed

+44
-84
lines changed

lib/backburner/binary-search.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
export default function binarySearch(time, timers) {
22
let start = 0;
3-
let end = timers.length - 6;
3+
let end = timers.length - 7;
44
let middle;
55
let l;
66

77
while (start < end) {
88
// since timers is an array of pairs 'l' will always
99
// be an integer
10-
l = (end - start) / 6;
10+
l = (end - start) / 7;
1111

1212
// compensate for the index in case even number
1313
// of pairs inside timers
14-
middle = start + l - (l % 6);
14+
middle = start + l - (l % 7);
1515

1616
if (time >= timers[middle]) {
17-
start = middle + 6;
17+
start = middle + 7;
1818
} else {
1919
end = middle;
2020
}
2121
}
2222

23-
return (time >= timers[start]) ? start + 6 : start;
23+
return (time >= timers[start]) ? start + 7 : start;
2424
}

lib/backburner/utils.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ export function findItem(target, method, collection) {
2222
return index;
2323
}
2424

25-
export function findTimer(timer, collection) {
25+
export function findTimerItem(target, method, collection) {
2626
let index = -1;
2727

28-
for (let i = 3; i < collection.length; i += 4) {
29-
if (collection[i] === timer) {
30-
index = i - 3;
28+
for (let i = 2, l = collection.length; i < l; i += 7) {
29+
if (collection[i] === target && collection[i + 1] === method) {
30+
index = i - 2;
3131
break;
3232
}
3333
}

lib/index.ts

Lines changed: 34 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ import {
88
IPlatform,
99
} from './backburner/platform';
1010
import {
11-
findItem,
12-
findTimer,
11+
findTimerItem,
1312
getOnError,
1413
isCoercableNumber
1514
} from './backburner/utils';
@@ -193,8 +192,6 @@ export default class Backburner {
193192
private _onEnd: (currentInstance: DeferredActionQueues, nextInstance: DeferredActionQueues | null) => void;
194193
private queueNames: string[];
195194
private instanceStack: DeferredActionQueues[] = [];
196-
private _debouncees: any[] = [];
197-
private _throttlers: any[] = [];
198195
private _eventCallbacks: {
199196
end: Function[];
200197
begin: Function[];
@@ -450,26 +447,21 @@ export default class Backburner {
450447
throttleCount++;
451448
let [target, method, args, wait, isImmediate = true] = parseDebounceArgs(...arguments);
452449

453-
let index = findItem(target, method, this._throttlers);
450+
let index = findTimerItem(target, method, this._timers);
454451
if (index > -1) {
455-
this._throttlers[index + 2] = args;
456-
return this._throttlers[index + 3];
457-
} // throttled
452+
let timerId = this._timers[index + 1];
453+
this._timers[index + 4] = args;
454+
return timerId;
455+
}
458456

459-
let timer = this._platform.setTimeout(() => {
460-
let i = findTimer(timer, this._throttlers);
461-
let [context, func, params] = this._throttlers.splice(i, 4);
462-
if (isImmediate === false) {
463-
this._run(context, func, params);
464-
}
465-
}, wait);
457+
wait = parseInt(wait, 10);
458+
459+
let timer = this._later(target, method, args, wait, isImmediate);
466460

467461
if (isImmediate) {
468462
this._join(target, method, args);
469463
}
470464

471-
this._throttlers.push(target, method, args, timer);
472-
473465
return timer;
474466
}
475467

@@ -495,64 +487,40 @@ export default class Backburner {
495487
let [target, method, args, wait, isImmediate = false] = parseDebounceArgs(...arguments);
496488

497489
// Remove debouncee
498-
let index = findItem(target, method, this._debouncees);
490+
let index = findTimerItem(target, method, this._timers);
499491
if (index > -1) {
500-
let timerId = this._debouncees[index + 3];
501-
this._platform.clearTimeout(timerId);
502-
this._debouncees.splice(index, 4);
492+
this._timers.splice(index, 7);
493+
if (index === 0) {
494+
this._reinstallTimerTimeout();
495+
}
503496
}
504497

505-
let timer = this._platform.setTimeout(() => {
506-
let i = findTimer(timer, this._debouncees);
507-
let [context, func, params] = this._debouncees.splice(i, 4);
508-
if (isImmediate === false) {
509-
this._run(context, func, params);
510-
}
511-
}, wait);
498+
let timer = this._later(target, method, args, wait, isImmediate);
512499

513500
if (isImmediate && index === -1) {
514501
this._join(target, method, args);
515502
}
516503

517-
this._debouncees.push(target, method, args, timer);
518-
519504
return timer;
520505
}
521506

522507
public cancelTimers() {
523508
cancelTimersCount++;
524-
for (let i = 3; i < this._throttlers.length; i += 4) {
525-
this._platform.clearTimeout(this._throttlers[i]);
526-
}
527-
this._throttlers = [];
528-
529-
for (let t = 3; t < this._debouncees.length; t += 4) {
530-
this._platform.clearTimeout(this._debouncees[t]);
531-
}
532-
this._debouncees = [];
533-
534509
this._clearTimerTimeout();
535510
this._timers = [];
536-
537511
this._cancelAutorun();
538512
}
539513

540514
public hasTimers() {
541-
return this._timers.length > 0 ||
542-
this._debouncees.length > 0 ||
543-
this._throttlers.length > 0 ||
544-
this._autorun !== null;
515+
return this._timers.length > 0 || this._autorun !== null;
545516
}
546517

547518
public cancel(timer?) {
548519
cancelCount++;
549-
550-
if (timer === undefined || timer === null) { return false; }
551-
520+
if (timer === null || timer === undefined) { return false; }
552521
let timerType = typeof timer;
553-
if (timerType === 'number') { // we're cancelling a throttle or debounce
554-
return this._cancelItem(timer, this._throttlers) || this._cancelItem(timer, this._debouncees);
555-
} else if (timerType === 'string') { // we're cancelling a setTimeout
522+
523+
if (timerType === 'number') { // we're cancelling a setTimeout or throttle or debounce
556524
return this._cancelLaterTimer(timer);
557525
} else if (timerType === 'object' && timer.queue && timer.method) { // we're cancelling a deferOnce
558526
return timer.queue.cancel(timer);
@@ -640,18 +608,18 @@ export default class Backburner {
640608
}
641609
}
642610

643-
private _later(target, method, args, wait) {
611+
private _later(target, method, args, wait, isImmediate = false) {
644612
let stack = this.DEBUG ? new Error() : undefined;
645613
let executeAt = this._platform.now() + wait;
646-
let id = (UUID++) + '';
614+
let id = UUID++;
647615

648616
if (this._timers.length === 0) {
649-
this._timers.push(executeAt, id, target, method, args, stack);
617+
this._timers.push(executeAt, id, target, method, args, isImmediate, stack);
650618
this._installTimerTimeout();
651619
} else {
652620
// find position to insert
653621
let i = searchTimer(executeAt, this._timers);
654-
this._timers.splice(i, 0, executeAt, id, target, method, args, stack);
622+
this._timers.splice(i, 0, executeAt, id, target, method, args, isImmediate, stack);
655623

656624
// we should be the new earliest timer if i == 0
657625
if (i === 0) {
@@ -662,10 +630,10 @@ export default class Backburner {
662630
}
663631

664632
private _cancelLaterTimer(timer) {
665-
for (let i = 1; i < this._timers.length; i += 6) {
633+
for (let i = 1; i < this._timers.length; i += 7) {
666634
if (this._timers[i] === timer) {
667635
i = i - 1;
668-
this._timers.splice(i, 6);
636+
this._timers.splice(i, 7);
669637
if (i === 0) {
670638
this._reinstallTimerTimeout();
671639
}
@@ -675,17 +643,6 @@ export default class Backburner {
675643
return false;
676644
}
677645

678-
private _cancelItem(timer, array) {
679-
let index = findTimer(timer, array);
680-
681-
if (index > -1) {
682-
this._platform.clearTimeout(timer);
683-
array.splice(index, 4);
684-
return true;
685-
}
686-
return false;
687-
}
688-
689646
/**
690647
Trigger an event. Supports up to two arguments. Designed around
691648
triggering transition events from one run loop instance to the
@@ -723,15 +680,17 @@ export default class Backburner {
723680
let defaultQueue = this._defaultQueue;
724681
let n = this._platform.now();
725682

726-
for (; i < l; i += 6) {
683+
for (; i < l; i += 7) {
727684
let executeAt = timers[i];
728685
if (executeAt > n) { break; }
729-
730-
let target = timers[i + 2];
731-
let method = timers[i + 3];
732-
let args = timers[i + 4];
733-
let stack = timers[i + 5];
734-
this.currentInstance!.schedule(defaultQueue, target, method, args, false, stack);
686+
let isImmediate = timers[i + 5];
687+
if (isImmediate === false) {
688+
let target = timers[i + 2];
689+
let method = timers[i + 3];
690+
let args = timers[i + 4];
691+
let stack = timers[i + 6];
692+
this.currentInstance!.schedule(defaultQueue, target, method, args, false, stack);
693+
}
735694
}
736695

737696
timers.splice(0, i);

tests/bb-has-timers-test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ QUnit.test('hasTimers', function(assert) {
1717
assert.ok(bb.hasTimers(), 'hasTimers checks timers');
1818

1919
bb.cancel(timer);
20+
2021
assert.ok(!bb.hasTimers(), 'Timers are cleared');
2122

2223
timer = bb.debounce(target, 'fn', 200);

0 commit comments

Comments
 (0)