Support `options` param for `requestIdleCallback`
Summary: The `requestIdleCallback` sometimes doesn't work in `Debug JS Remotely` mode if I use real device, the callback will never called. I guess it may be debugger worker and device caused by the time gap, or some cause websocket blocking, so it's just sometimes happening. I think we can support [options](https://developer.mozilla.org/zh-TW/docs/Web/API/Window/requestIdleCallback#Parameters) for that. Added an example `Run requestIdleCallback with timeout option` for Timers of UIExplorer, it use `{ timeout: 100 }` option with burn CPU 100ms, we can see `didTimeout` is true. Closes https://github.com/facebook/react-native/pull/13116 Differential Revision: D4894348 Pulled By: hramos fbshipit-source-id: 29c4c2fe5634b30a8bf8d3495305cd8f635ed922
This commit is contained in:
parent
b975342e7b
commit
cf51aee9a0
|
@ -17,6 +17,7 @@ const JSTimersExecution = require('JSTimersExecution');
|
|||
const Platform = require('Platform');
|
||||
|
||||
const {Timing} = require('NativeModules');
|
||||
const performanceNow = require('fbjs/lib/performanceNow');
|
||||
|
||||
import type {JSTimerType} from 'JSTimersExecution';
|
||||
|
||||
|
@ -131,14 +132,43 @@ const JSTimers = {
|
|||
/**
|
||||
* @param {function} func Callback to be invoked every frame and provided
|
||||
* with time remaining in frame.
|
||||
* @param {?object} options
|
||||
*/
|
||||
requestIdleCallback: function(func : Function) {
|
||||
requestIdleCallback: function(func : Function, options : ?Object) {
|
||||
if (JSTimersExecution.requestIdleCallbacks.length === 0) {
|
||||
Timing.setSendIdleEvents(true);
|
||||
}
|
||||
|
||||
const id = _allocateCallback(func, 'requestIdleCallback');
|
||||
const timeout = options && options.timeout;
|
||||
const id = _allocateCallback(
|
||||
timeout != null ?
|
||||
deadline => {
|
||||
const timeoutId = JSTimersExecution.requestIdleCallbackTimeouts.get(id);
|
||||
if (timeoutId) {
|
||||
JSTimers.clearTimeout(timeoutId);
|
||||
JSTimersExecution.requestIdleCallbackTimeouts.delete(id);
|
||||
}
|
||||
return func(deadline);
|
||||
} :
|
||||
func,
|
||||
'requestIdleCallback'
|
||||
);
|
||||
JSTimersExecution.requestIdleCallbacks.push(id);
|
||||
|
||||
if (timeout != null) {
|
||||
const timeoutId = JSTimers.setTimeout(() => {
|
||||
const index = JSTimersExecution.requestIdleCallbacks.indexOf(id);
|
||||
if (index > -1) {
|
||||
JSTimersExecution.requestIdleCallbacks.splice(index, 1);
|
||||
JSTimersExecution.callTimer(id, performanceNow(), true);
|
||||
}
|
||||
JSTimersExecution.requestIdleCallbackTimeouts.delete(id);
|
||||
if (JSTimersExecution.requestIdleCallbacks.length === 0) {
|
||||
Timing.setSendIdleEvents(false);
|
||||
}
|
||||
}, timeout);
|
||||
JSTimersExecution.requestIdleCallbackTimeouts.set(id, timeoutId);
|
||||
}
|
||||
return id;
|
||||
},
|
||||
|
||||
|
@ -149,6 +179,12 @@ const JSTimers = {
|
|||
JSTimersExecution.requestIdleCallbacks.splice(index, 1);
|
||||
}
|
||||
|
||||
const timeoutId = JSTimersExecution.requestIdleCallbackTimeouts.get(timerID);
|
||||
if (timeoutId) {
|
||||
JSTimers.clearTimeout(timeoutId);
|
||||
JSTimersExecution.requestIdleCallbackTimeouts.delete(timerID);
|
||||
}
|
||||
|
||||
if (JSTimersExecution.requestIdleCallbacks.length === 0) {
|
||||
Timing.setSendIdleEvents(false);
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ const JSTimersExecution = {
|
|||
timerIDs: ([] : Array<?number>),
|
||||
immediates: [],
|
||||
requestIdleCallbacks: [],
|
||||
requestIdleCallbackTimeouts: (new Map() : Map<number, number>),
|
||||
identifiers: ([] : Array<null | {methodName: string}>),
|
||||
|
||||
errors: (null : ?Array<Error>),
|
||||
|
@ -54,7 +55,7 @@ const JSTimersExecution = {
|
|||
* if it was a one time timer (setTimeout), and not unregister it if it was
|
||||
* recurring (setInterval).
|
||||
*/
|
||||
callTimer(timerID: number, frameTime: number) {
|
||||
callTimer(timerID: number, frameTime: number, didTimeout: ?boolean) {
|
||||
warning(
|
||||
timerID <= JSTimersExecution.GUID,
|
||||
'Tried to call timer with ID %s but no such timer exists.',
|
||||
|
@ -103,6 +104,7 @@ const JSTimersExecution = {
|
|||
// would require a way to check the bridge queue synchronously.
|
||||
return Math.max(0, FRAME_DURATION - (performanceNow() - frameTime));
|
||||
},
|
||||
didTimeout: !!didTimeout,
|
||||
});
|
||||
} else {
|
||||
console.error('Tried to call a callback with invalid type: ' + type);
|
||||
|
|
|
@ -52,6 +52,10 @@ class RequestIdleCallbackTester extends React.Component {
|
|||
Burn CPU inside of requestIdleCallback
|
||||
</RNTesterButton>
|
||||
|
||||
<RNTesterButton onPress={this._runWithTimeout.bind(this)}>
|
||||
Run requestIdleCallback with timeout option
|
||||
</RNTesterButton>
|
||||
|
||||
<RNTesterButton onPress={this._runBackground}>
|
||||
Run background task
|
||||
</RNTesterButton>
|
||||
|
@ -78,6 +82,16 @@ class RequestIdleCallbackTester extends React.Component {
|
|||
});
|
||||
};
|
||||
|
||||
_runWithTimeout = () => {
|
||||
cancelIdleCallback(this._idleTimer);
|
||||
this._idleTimer = requestIdleCallback((deadline) => {
|
||||
this.setState({
|
||||
message: `${deadline.timeRemaining()}ms remaining in frame, it did timeout: ${deadline.didTimeout ? 'yes' : 'no'}`
|
||||
});
|
||||
}, { timeout: 100 });
|
||||
burnCPU(100);
|
||||
};
|
||||
|
||||
_runBackground = () => {
|
||||
cancelIdleCallback(this._idleTimer);
|
||||
const handler = (deadline) => {
|
||||
|
|
Loading…
Reference in New Issue