Skip to content

Enable flush timing to be controlled from the host. #363

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Merged
merged 1 commit into from
Mar 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/backburner/deferred-action-queues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ export interface IDebugInfo {

export default class DeferredActionQueues {
public queues: { [name: string]: Queue } = {};
public queueNameIndex = 0;

private queueNames: string[];
private queueNameIndex = 0;

constructor(queueNames: string[] = [], options: any) {
this.queueNames = queueNames;
Expand Down
2 changes: 1 addition & 1 deletion lib/backburner/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export interface IPlatform {
setTimeout(fn: Function, ms: number): any;
clearTimeout(id: any): void;
next(): any;
clearNext(timerId: any): void;
clearNext(): void;
now(): number;
}

Expand Down
34 changes: 22 additions & 12 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ export interface IBackburnerOptions {
onErrorMethod?: string;
mustYield?: () => boolean;
_buildPlatform?: (flush: () => void) => IPlatform;
flush?(queueName: string, flush: () => void): void;
}

export default class Backburner {
Expand Down Expand Up @@ -213,7 +214,7 @@ export default class Backburner {

private _boundRunExpiredTimers: () => void;

private _autorun: number | null = null;
private _autorun = false;
private _autorunStack: Error | undefined | null = null;
private _boundAutorunEnd: () => void;
private _defaultQueue: string;
Expand All @@ -236,9 +237,9 @@ export default class Backburner {
autorunsCompletedCount++;

// if the autorun was already flushed, do nothing
if (this._autorun === null) { return; }
if (this._autorun === false) { return; }

this._autorun = null;
this._autorun = false;
this._autorunStack = null;
this._end(true /* fromAutorun */);
};
Expand All @@ -260,7 +261,7 @@ export default class Backburner {
let previousInstance = this.currentInstance;
let current;

if (this._autorun !== null) {
if (this._autorun !== false) {
current = previousInstance;
this._cancelAutorun();
} else {
Expand Down Expand Up @@ -540,7 +541,7 @@ export default class Backburner {
}

public hasTimers() {
return this._timers.length > 0 || this._autorun !== null;
return this._timers.length > 0 || this._autorun;
}

public cancel(timer?) {
Expand Down Expand Up @@ -601,7 +602,8 @@ export default class Backburner {
finallyAlreadyCalled = true;

if (result === QUEUE_STATE.Pause) {
this._scheduleAutorun();
const plannedNextQueue = this.queueNames[currentInstance.queueNameIndex];
this._scheduleAutorun(plannedNextQueue);
} else {
this.currentInstance = null;

Expand Down Expand Up @@ -651,9 +653,9 @@ export default class Backburner {
}

private _cancelAutorun() {
if (this._autorun !== null) {
this._platform.clearNext(this._autorun);
this._autorun = null;
if (this._autorun) {
this._platform.clearNext();
this._autorun = false;
this._autorunStack = null;
}
}
Expand Down Expand Up @@ -767,15 +769,23 @@ export default class Backburner {
if (currentInstance === null) {
this._autorunStack = this.DEBUG ? new Error() : undefined;
currentInstance = this.begin();
this._scheduleAutorun();
this._scheduleAutorun(this.queueNames[0]);
}
return currentInstance;
}

private _scheduleAutorun() {
private _scheduleAutorun(plannedNextQueue: string) {
autorunsCreatedCount++;

const next = this._platform.next;
this._autorun = next();
const flush = this.options.flush;

if (flush) {
flush(plannedNextQueue, next);
} else {
next();
}

this._autorun = true;
}
}
158 changes: 158 additions & 0 deletions tests/autorun-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ import lolex from 'lolex';
const SET_TIMEOUT = setTimeout;
let fakeClock;

function escapeCurrentMicrotaskQueue() {
return new Promise((resolve) => {
// this ensures that we have been to the end of the current
// events microtask queue
setTimeout(resolve, 0);
});
}

QUnit.module('tests/autorun', {
afterEach() {
if (fakeClock) {
Expand Down Expand Up @@ -162,3 +170,153 @@ QUnit.test('autorun functions even when using fake timers', function(assert) {
assert.ok(bb.currentInstance, 'The DeferredActionQueues object exists');
assert.equal(step++, 1);
});

QUnit.test('customizing flushing per queue via flush', function(assert) {
assert.step('start');

let deferredFlush;

let bb = new Backburner(
[
'zomg',
'render',
'afterRender'
],
{
flush(queueName, flush) {
if (queueName === 'render') {
deferredFlush = flush;
} else {
flush();
}
}
}
);

bb.schedule('zomg', null, () => {
assert.step('running zomg');
});

bb.schedule('render', null, () => {
assert.step('running render');
});

bb.schedule('afterRender', null, () => {
assert.step('running afterRender');
});

return escapeCurrentMicrotaskQueue()
.then(() => {
deferredFlush();
})
.then(escapeCurrentMicrotaskQueue)
.then(() => {
assert.verifySteps([
'start',
'running zomg',
'running render',
'running afterRender',
]);
});
});

QUnit.test('customized flushing - precedence is rechecked upon each flush', function(assert) {
assert.step('start');

let deferredFlush;

let bb = new Backburner(
[
'zomg',
'render',
'afterRender'
],
{
flush(queueName, flush) {
if (deferredFlush === undefined && queueName === 'render') {
deferredFlush = flush;
} else {
flush();
}
}
}
);

bb.schedule('zomg', null, () => {
assert.step('running zomg');
});

bb.schedule('render', null, () => {
assert.step('running render');
});

bb.schedule('afterRender', null, () => {
assert.step('running afterRender');
});

return escapeCurrentMicrotaskQueue()
.then(() => {
bb.schedule('zomg', null, () => {
assert.step('running zomg 2');
});

deferredFlush();
})
.then(escapeCurrentMicrotaskQueue)
.then(() => {
assert.verifySteps([
'start',
'running zomg',
'running zomg 2',
'running render',
'running afterRender',
]);
});
});

QUnit.test('customizing flushing per queue via flush - with forced run', function(assert) {
assert.step('start');

let deferredFlush;

let bb = new Backburner(
[
'zomg',
'render',
'afterRender'
],
{
flush(queueName, flush) {
if (queueName === 'render') {
deferredFlush = flush;
} else {
flush();
}
}
}
);

bb.schedule('zomg', null, () => {
assert.step('running zomg');
});

bb.schedule('render', null, () => {
assert.step('running render');
});

bb.schedule('afterRender', null, () => {
assert.step('running afterRender');
});

return escapeCurrentMicrotaskQueue()
.then(() => {
bb.run(() => {});

assert.verifySteps([
'start',
'running zomg',
'running render',
'running afterRender',
]);
});
});
3 changes: 1 addition & 2 deletions tests/configurable-timeout-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,8 @@ QUnit.test('We can use a custom clearTimeout', function(assert) {
next() {
return setTimeout(flush, 0);
},
clearNext(timer) {
clearNext() {
customClearTimeoutWasUsed = true;
return clearTimeout(timer);
},
now() {
return Date.now();
Expand Down