Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Expiration times #10426

Merged
merged 10 commits into from
Oct 10, 2017
81 changes: 42 additions & 39 deletions fixtures/fiber-triangle/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -76,51 +76,54 @@ <h1>Fiber Example</h1>
}
}

function SierpinskiTriangle({ x, y, s, children }) {
if (s <= targetSize) {
return (
<Dot
x={x - (targetSize / 2)}
y={y - (targetSize / 2)}
size={targetSize}
text={children}
/>
class SierpinskiTriangle extends React.Component {
shouldComponentUpdate(nextProps) {
var o = this.props;
var n = nextProps;
return !(
o.x === n.x &&
o.y === n.y &&
o.s === n.s &&
o.children === n.children
);
return r;
}
var newSize = s / 2;
var slowDown = true;
if (slowDown) {
var e = performance.now() + 0.8;
while (performance.now() < e) {
// Artificially long execution time.
render() {
let {x, y, s, children} = this.props;
if (s <= targetSize) {
return (
<Dot
x={x - (targetSize / 2)}
y={y - (targetSize / 2)}
size={targetSize}
text={children}
/>
);
return r;
}
var newSize = s / 2;
var slowDown = true;
if (slowDown) {
var e = performance.now() + 0.8;
while (performance.now() < e) {
// Artificially long execution time.
}
}
}

s /= 2;
s /= 2;

return [
<SierpinskiTriangle x={x} y={y - (s / 2)} s={s}>
{children}
</SierpinskiTriangle>,
<SierpinskiTriangle x={x - s} y={y + (s / 2)} s={s}>
{children}
</SierpinskiTriangle>,
<SierpinskiTriangle x={x + s} y={y + (s / 2)} s={s}>
{children}
</SierpinskiTriangle>,
];
return [
<SierpinskiTriangle x={x} y={y - (s / 2)} s={s}>
{children}
</SierpinskiTriangle>,
<SierpinskiTriangle x={x - s} y={y + (s / 2)} s={s}>
{children}
</SierpinskiTriangle>,
<SierpinskiTriangle x={x + s} y={y + (s / 2)} s={s}>
{children}
</SierpinskiTriangle>,
];
}
}
SierpinskiTriangle.shouldComponentUpdate = function(oldProps, newProps) {
var o = oldProps;
var n = newProps;
return !(
o.x === n.x &&
o.y === n.y &&
o.s === n.s &&
o.children === n.children
);
};

class ExampleApplication extends React.Component {
constructor() {
Expand Down
2 changes: 2 additions & 0 deletions src/renderers/art/ReactARTFiberEntry.js
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,8 @@ const ARTRenderer = ReactFiberReconciler({
);
},

now: ReactDOMFrameScheduling.now,

useSyncScheduling: true,
});

Expand Down
2 changes: 2 additions & 0 deletions src/renderers/dom/fiber/ReactDOMFiberEntry.js
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,8 @@ var DOMRenderer = ReactFiberReconciler({
}
},

now: ReactDOMFrameScheduling.now,

canHydrateInstance(
instance: Instance | TextInstance,
type: string,
Expand Down
5 changes: 5 additions & 0 deletions src/renderers/native-rt/ReactNativeRTFiberRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,11 @@ const NativeRTRenderer = ReactFiberReconciler({
},

useSyncScheduling: true,

now(): number {
// TODO: Enable expiration by implementing this method.
return 0;
},
});

module.exports = NativeRTRenderer;
5 changes: 5 additions & 0 deletions src/renderers/native/ReactNativeFiberRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,11 @@ const NativeRenderer = ReactFiberReconciler({
},

useSyncScheduling: true,

now(): number {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this added to ReactNativeFiberRenderer and not ReactNativeFiberEntry?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Entry" modules are the public API. The renderer is what you create out of a host config. For whatever reason, our React Native renderer splits the two into separate files, whereas our DOM renderer does not. Don't think there's any real reason, just happened to be factored that way.

// TODO: Enable expiration by implementing this method.
return 0;
},
});

module.exports = NativeRenderer;
20 changes: 17 additions & 3 deletions src/renderers/noop/ReactNoopEntry.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ function removeChild(
parentInstance.children.splice(index, 1);
}

let elapsedTimeInMs = 0;

var NoopRenderer = ReactFiberReconciler({
getRootHostContext() {
if (failInBeginPhase) {
Expand Down Expand Up @@ -201,6 +203,10 @@ var NoopRenderer = ReactFiberReconciler({
prepareForCommit(): void {},

resetAfterCommit(): void {},

now(): number {
return elapsedTimeInMs;
},
});

var rootContainers = new Map();
Expand Down Expand Up @@ -336,6 +342,14 @@ var ReactNoop = {
expect(actual).toEqual(expected);
},

expire(ms: number): void {
elapsedTimeInMs += ms;
},

flushExpired(): Array<mixed> {
return ReactNoop.flushUnitsOfWork(0);
},

yield(value: mixed) {
if (yieldedValues === null) {
yieldedValues = [value];
Expand Down Expand Up @@ -400,15 +414,15 @@ var ReactNoop = {
' '.repeat(depth + 1) + '~',
firstUpdate && firstUpdate.partialState,
firstUpdate.callback ? 'with callback' : '',
'[' + firstUpdate.priorityLevel + ']',
'[' + firstUpdate.expirationTime + ']',
);
var next;
while ((next = firstUpdate.next)) {
log(
' '.repeat(depth + 1) + '~',
next.partialState,
next.callback ? 'with callback' : '',
'[' + firstUpdate.priorityLevel + ']',
'[' + firstUpdate.expirationTime + ']',
);
}
}
Expand All @@ -418,7 +432,7 @@ var ReactNoop = {
' '.repeat(depth) +
'- ' +
(fiber.type ? fiber.type.name || fiber.type : '[root]'),
'[' + fiber.pendingWorkPriority + (fiber.pendingProps ? '*' : '') + ']',
'[' + fiber.expirationTime + (fiber.pendingProps ? '*' : '') + ']',
);
if (fiber.updateQueue) {
logUpdateQueue(fiber.updateQueue, depth);
Expand Down
45 changes: 32 additions & 13 deletions src/renderers/shared/ReactDOMFrameScheduling.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,20 @@ if (__DEV__) {
}
}

const hasNativePerformanceNow =
typeof performance === 'object' && typeof performance.now === 'function';

let now;
if (hasNativePerformanceNow) {
now = function() {
return performance.now();
};
} else {
now = function() {
return Date.now();
};
}

// TODO: There's no way to cancel, because Fiber doesn't atm.
let rIC: (callback: (deadline: Deadline) => void) => number;

Expand Down Expand Up @@ -67,19 +81,23 @@ if (!ExecutionEnvironment.canUseDOM) {
var previousFrameTime = 33;
var activeFrameTime = 33;

var frameDeadlineObject = {
timeRemaining: typeof performance === 'object' &&
typeof performance.now === 'function'
? function() {
// We assume that if we have a performance timer that the rAF callback
// gets a performance timer value. Not sure if this is always true.
return frameDeadline - performance.now();
}
: function() {
// As a fallback we use Date.now.
return frameDeadline - Date.now();
},
};
var frameDeadlineObject;
if (hasNativePerformanceNow) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why we do the judgement again instead calling now() directly?

frameDeadlineObject = {
timeRemaining() {
// We assume that if we have a performance timer that the rAF callback
// gets a performance timer value. Not sure if this is always true.
return frameDeadline - performance.now();
},
};
} else {
frameDeadlineObject = {
timeRemaining() {
// Fallback to Date.now()
return frameDeadline - Date.now();
},
};
}

// We use the postMessage trick to defer idle work until after the repaint.
var messageKey = '__reactIdleCallback$' + Math.random().toString(36).slice(2);
Expand Down Expand Up @@ -153,4 +171,5 @@ if (!ExecutionEnvironment.canUseDOM) {
rIC = requestIdleCallback;
}

exports.now = now;
exports.rIC = rIC;
Loading