Add additional scheduling tests

Tests whether certain types of work can be performed after the deadline
has expired.
This commit is contained in:
Andrew Clark
2016-12-07 23:09:08 -08:00
committed by Andrew Clark
parent 3a7844cabb
commit f56eb89389
5 changed files with 78 additions and 13 deletions
+2
View File
@@ -1150,6 +1150,8 @@ src/renderers/shared/fiber/__tests__/ReactIncrementalScheduling-test.js
* handles interleaved deferred and animation work
* schedules sync updates when inside componentDidMount/Update
* can opt-in to deferred/animation scheduling inside componentDidMount/Update
* performs Task work even after time runs out
* does not perform animation work after time runs out
src/renderers/shared/fiber/__tests__/ReactIncrementalSideEffects-test.js
* can update child nodes of a host instance
@@ -548,7 +548,9 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
nextUnitOfWork = findNextUnitOfWork();
}
if (deadline) {
// If there's a deadline, and we're not performing Task work, perform work
// using this loop that checks the deadline on every iteration.
if (deadline && priorityLevel > TaskPriority) {
// The deferred work loop will run until there's no time left in
// the current frame.
while (nextUnitOfWork && !deadlineHasExpired) {
@@ -575,13 +577,9 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
}
}
} else {
// The non-deferred work loop will run until there's no more work
// at the given priority level
if (priorityLevel >= HighPriority) {
throw new Error(
'Deferred work should only be performed using deferredWorkLoop'
);
}
// If there's no deadline, or if we're performing Task work, use this loop
// that doesn't check how much time is remaining. It will keep running
// until we run out of work at this priority level.
while (nextUnitOfWork &&
nextPriorityLevel !== NoWork &&
nextPriorityLevel <= priorityLevel) {
@@ -610,6 +608,12 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
// catching an error. It also lets us flush Task work at the end of a
// deferred batch.
while (priorityLevel !== NoWork) {
if (priorityLevel >= HighPriority && !deadline) {
throw new Error(
'Cannot perform deferred work without a deadline.'
);
}
// Before starting any work, check to see if there are any pending
// commits from the previous frame. An exception is if we're flushing
// Task work in a deferred batch and the pending commit does not
@@ -410,7 +410,7 @@ describe('ReactIncremental', () => {
// Make a quick update which will create a low pri tree on top of the
// already low pri tree.
ReactNoop.render(<Foo text="bar" />);
ReactNoop.flushDeferredPri(15 + 5);
ReactNoop.flushDeferredPri(15);
expect(ops).toEqual(['Foo']);
@@ -93,7 +93,7 @@ describe('ReactIncrementalErrorHandling', () => {
expect(ReactNoop.getChildren()).toEqual([]);
ops.length = 0;
ReactNoop.flushDeferredPri(25 + 10);
ReactNoop.flushDeferredPri(30);
expect(ops).toEqual([
'BrokenRender',
'ErrorBoundary unstable_handleError',
@@ -341,7 +341,7 @@ describe('ReactIncrementalScheduling', () => {
expect(ReactNoop.getChildren('b')).toEqual([]);
expect(ReactNoop.getChildren('c')).toEqual(null);
// Then the second one gets processed
ReactNoop.flushDeferredPri(15 + 5 + 5);
ReactNoop.flushDeferredPri(15 + 5);
expect(ReactNoop.getChildren('a')).toEqual([span('a:2')]);
expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]);
expect(ReactNoop.getChildren('c')).toEqual(null);
@@ -483,7 +483,7 @@ describe('ReactIncrementalScheduling', () => {
ReactNoop.render(<Foo />);
ReactNoop.flushDeferredPri(5 + 20 + 20);
ReactNoop.flushDeferredPri(20 + 5);
expect(ops).toEqual([
'render: 0',
'componentDidMount (before setState): 0',
@@ -496,7 +496,7 @@ describe('ReactIncrementalScheduling', () => {
ops = [];
instance.setState({ tick: 2 });
ReactNoop.flushDeferredPri(5 + 20 + 20);
ReactNoop.flushDeferredPri(20 + 5);
expect(ops).toEqual([
'render: 2',
@@ -587,4 +587,63 @@ describe('ReactIncrementalScheduling', () => {
'componentDidUpdate: 3',
]);
});
it('performs Task work even after time runs out', () => {
class Foo extends React.Component {
state = { step: 1 };
componentDidMount() {
this.setState({ step: 2 }, () => {
this.setState({ step: 3 }, () => {
this.setState({ step: 4 }, () => {
this.setState({ step: 5 });
});
});
});
}
render() {
return <span prop={this.state.step} />;
}
}
ReactNoop.render(<Foo />);
// This should be just enough to complete all the work, but not enough to
// commit it.
ReactNoop.flushDeferredPri(20);
expect(ReactNoop.getChildren()).toEqual([]);
// Do one more unit of work.
ReactNoop.flushDeferredPri(10);
// The updates should all be flushed with Task priority
expect(ReactNoop.getChildren()).toEqual([span(5)]);
});
it('does not perform animation work after time runs out', () => {
class Foo extends React.Component {
state = { step: 1 };
componentDidMount() {
ReactNoop.performAnimationWork(() => {
this.setState({ step: 2 }, () => {
this.setState({ step: 3 }, () => {
this.setState({ step: 4 }, () => {
this.setState({ step: 5 });
});
});
});
});
}
render() {
return <span prop={this.state.step} />;
}
}
ReactNoop.render(<Foo />);
// This should be just enough to complete all the work, but not enough to
// commit it.
ReactNoop.flushDeferredPri(20);
expect(ReactNoop.getChildren()).toEqual([]);
// Do one more unit of work.
ReactNoop.flushDeferredPri(10);
// None of the updates should be flushed because they only have
// animation priority.
expect(ReactNoop.getChildren()).toEqual([span(1)]);
});
});