Skip to content

Commit cfad13c

Browse files
authored
Merge pull request #363 from rwjblue/allow-customized-flushing
Enable flush timing to be controlled from the host.
2 parents 82e9d3f + a29d59e commit cfad13c

File tree

5 files changed

+183
-16
lines changed

5 files changed

+183
-16
lines changed

lib/backburner/deferred-action-queues.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ export interface IDebugInfo {
77

88
export default class DeferredActionQueues {
99
public queues: { [name: string]: Queue } = {};
10+
public queueNameIndex = 0;
1011

1112
private queueNames: string[];
12-
private queueNameIndex = 0;
1313

1414
constructor(queueNames: string[] = [], options: any) {
1515
this.queueNames = queueNames;

lib/backburner/platform.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ export interface IPlatform {
22
setTimeout(fn: Function, ms: number): any;
33
clearTimeout(id: any): void;
44
next(): any;
5-
clearNext(timerId: any): void;
5+
clearNext(): void;
66
now(): number;
77
}
88

lib/index.ts

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ export interface IBackburnerOptions {
150150
onErrorMethod?: string;
151151
mustYield?: () => boolean;
152152
_buildPlatform?: (flush: () => void) => IPlatform;
153+
flush?(queueName: string, flush: () => void): void;
153154
}
154155

155156
export default class Backburner {
@@ -213,7 +214,7 @@ export default class Backburner {
213214

214215
private _boundRunExpiredTimers: () => void;
215216

216-
private _autorun: number | null = null;
217+
private _autorun = false;
217218
private _autorunStack: Error | undefined | null = null;
218219
private _boundAutorunEnd: () => void;
219220
private _defaultQueue: string;
@@ -236,9 +237,9 @@ export default class Backburner {
236237
autorunsCompletedCount++;
237238

238239
// if the autorun was already flushed, do nothing
239-
if (this._autorun === null) { return; }
240+
if (this._autorun === false) { return; }
240241

241-
this._autorun = null;
242+
this._autorun = false;
242243
this._autorunStack = null;
243244
this._end(true /* fromAutorun */);
244245
};
@@ -260,7 +261,7 @@ export default class Backburner {
260261
let previousInstance = this.currentInstance;
261262
let current;
262263

263-
if (this._autorun !== null) {
264+
if (this._autorun !== false) {
264265
current = previousInstance;
265266
this._cancelAutorun();
266267
} else {
@@ -540,7 +541,7 @@ export default class Backburner {
540541
}
541542

542543
public hasTimers() {
543-
return this._timers.length > 0 || this._autorun !== null;
544+
return this._timers.length > 0 || this._autorun;
544545
}
545546

546547
public cancel(timer?) {
@@ -601,7 +602,8 @@ export default class Backburner {
601602
finallyAlreadyCalled = true;
602603

603604
if (result === QUEUE_STATE.Pause) {
604-
this._scheduleAutorun();
605+
const plannedNextQueue = this.queueNames[currentInstance.queueNameIndex];
606+
this._scheduleAutorun(plannedNextQueue);
605607
} else {
606608
this.currentInstance = null;
607609

@@ -651,9 +653,9 @@ export default class Backburner {
651653
}
652654

653655
private _cancelAutorun() {
654-
if (this._autorun !== null) {
655-
this._platform.clearNext(this._autorun);
656-
this._autorun = null;
656+
if (this._autorun) {
657+
this._platform.clearNext();
658+
this._autorun = false;
657659
this._autorunStack = null;
658660
}
659661
}
@@ -767,15 +769,23 @@ export default class Backburner {
767769
if (currentInstance === null) {
768770
this._autorunStack = this.DEBUG ? new Error() : undefined;
769771
currentInstance = this.begin();
770-
this._scheduleAutorun();
772+
this._scheduleAutorun(this.queueNames[0]);
771773
}
772774
return currentInstance;
773775
}
774776

775-
private _scheduleAutorun() {
777+
private _scheduleAutorun(plannedNextQueue: string) {
776778
autorunsCreatedCount++;
777779

778780
const next = this._platform.next;
779-
this._autorun = next();
781+
const flush = this.options.flush;
782+
783+
if (flush) {
784+
flush(plannedNextQueue, next);
785+
} else {
786+
next();
787+
}
788+
789+
this._autorun = true;
780790
}
781791
}

tests/autorun-test.ts

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ import lolex from 'lolex';
55
const SET_TIMEOUT = setTimeout;
66
let fakeClock;
77

8+
function escapeCurrentMicrotaskQueue() {
9+
return new Promise((resolve) => {
10+
// this ensures that we have been to the end of the current
11+
// events microtask queue
12+
setTimeout(resolve, 0);
13+
});
14+
}
15+
816
QUnit.module('tests/autorun', {
917
afterEach() {
1018
if (fakeClock) {
@@ -162,3 +170,153 @@ QUnit.test('autorun functions even when using fake timers', function(assert) {
162170
assert.ok(bb.currentInstance, 'The DeferredActionQueues object exists');
163171
assert.equal(step++, 1);
164172
});
173+
174+
QUnit.test('customizing flushing per queue via flush', function(assert) {
175+
assert.step('start');
176+
177+
let deferredFlush;
178+
179+
let bb = new Backburner(
180+
[
181+
'zomg',
182+
'render',
183+
'afterRender'
184+
],
185+
{
186+
flush(queueName, flush) {
187+
if (queueName === 'render') {
188+
deferredFlush = flush;
189+
} else {
190+
flush();
191+
}
192+
}
193+
}
194+
);
195+
196+
bb.schedule('zomg', null, () => {
197+
assert.step('running zomg');
198+
});
199+
200+
bb.schedule('render', null, () => {
201+
assert.step('running render');
202+
});
203+
204+
bb.schedule('afterRender', null, () => {
205+
assert.step('running afterRender');
206+
});
207+
208+
return escapeCurrentMicrotaskQueue()
209+
.then(() => {
210+
deferredFlush();
211+
})
212+
.then(escapeCurrentMicrotaskQueue)
213+
.then(() => {
214+
assert.verifySteps([
215+
'start',
216+
'running zomg',
217+
'running render',
218+
'running afterRender',
219+
]);
220+
});
221+
});
222+
223+
QUnit.test('customized flushing - precedence is rechecked upon each flush', function(assert) {
224+
assert.step('start');
225+
226+
let deferredFlush;
227+
228+
let bb = new Backburner(
229+
[
230+
'zomg',
231+
'render',
232+
'afterRender'
233+
],
234+
{
235+
flush(queueName, flush) {
236+
if (deferredFlush === undefined && queueName === 'render') {
237+
deferredFlush = flush;
238+
} else {
239+
flush();
240+
}
241+
}
242+
}
243+
);
244+
245+
bb.schedule('zomg', null, () => {
246+
assert.step('running zomg');
247+
});
248+
249+
bb.schedule('render', null, () => {
250+
assert.step('running render');
251+
});
252+
253+
bb.schedule('afterRender', null, () => {
254+
assert.step('running afterRender');
255+
});
256+
257+
return escapeCurrentMicrotaskQueue()
258+
.then(() => {
259+
bb.schedule('zomg', null, () => {
260+
assert.step('running zomg 2');
261+
});
262+
263+
deferredFlush();
264+
})
265+
.then(escapeCurrentMicrotaskQueue)
266+
.then(() => {
267+
assert.verifySteps([
268+
'start',
269+
'running zomg',
270+
'running zomg 2',
271+
'running render',
272+
'running afterRender',
273+
]);
274+
});
275+
});
276+
277+
QUnit.test('customizing flushing per queue via flush - with forced run', function(assert) {
278+
assert.step('start');
279+
280+
let deferredFlush;
281+
282+
let bb = new Backburner(
283+
[
284+
'zomg',
285+
'render',
286+
'afterRender'
287+
],
288+
{
289+
flush(queueName, flush) {
290+
if (queueName === 'render') {
291+
deferredFlush = flush;
292+
} else {
293+
flush();
294+
}
295+
}
296+
}
297+
);
298+
299+
bb.schedule('zomg', null, () => {
300+
assert.step('running zomg');
301+
});
302+
303+
bb.schedule('render', null, () => {
304+
assert.step('running render');
305+
});
306+
307+
bb.schedule('afterRender', null, () => {
308+
assert.step('running afterRender');
309+
});
310+
311+
return escapeCurrentMicrotaskQueue()
312+
.then(() => {
313+
bb.run(() => {});
314+
315+
assert.verifySteps([
316+
'start',
317+
'running zomg',
318+
'running render',
319+
'running afterRender',
320+
]);
321+
});
322+
});

tests/configurable-timeout-test.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,8 @@ QUnit.test('We can use a custom clearTimeout', function(assert) {
9999
next() {
100100
return setTimeout(flush, 0);
101101
},
102-
clearNext(timer) {
102+
clearNext() {
103103
customClearTimeoutWasUsed = true;
104-
return clearTimeout(timer);
105104
},
106105
now() {
107106
return Date.now();

0 commit comments

Comments
 (0)