mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Rename immediate to ReactNativeMicrotask in Bridge
Summary: Changelog: [Internal] This diff replaced all the internal occurrences of "Immediate" with "ReactNativeMicrotask" in the legacy bridge and then polyfilled the original immediate APIs during the timer setup phases as aliases of them. Note that this diff is part of a larger refactoring. Reviewed By: RSNara Differential Revision: D29785430 fbshipit-source-id: 7325d2a7358a6c9baa3e9abb8acf90414de5072f
This commit is contained in:
committed by
Facebook GitHub Bot
parent
893aff2e20
commit
37dc1d44a5
@@ -47,7 +47,7 @@ class MessageQueue {
|
||||
_callID: number;
|
||||
_lastFlush: number;
|
||||
_eventLoopStartTime: number;
|
||||
_immediatesCallback: ?() => void;
|
||||
_reactNativeMicrotasksCallback: ?() => void;
|
||||
|
||||
_debugInfo: {[number]: [number, number], ...};
|
||||
_remoteModuleTable: {[number]: string, ...};
|
||||
@@ -63,7 +63,7 @@ class MessageQueue {
|
||||
this._callID = 0;
|
||||
this._lastFlush = 0;
|
||||
this._eventLoopStartTime = Date.now();
|
||||
this._immediatesCallback = null;
|
||||
this._reactNativeMicrotasksCallback = null;
|
||||
|
||||
if (__DEV__) {
|
||||
this._debugInfo = {};
|
||||
@@ -132,7 +132,7 @@ class MessageQueue {
|
||||
|
||||
flushedQueue(): null | [Array<number>, Array<number>, Array<mixed>, number] {
|
||||
this.__guard(() => {
|
||||
this.__callImmediates();
|
||||
this.__callReactNativeMicrotasks();
|
||||
});
|
||||
|
||||
const queue = this._queue;
|
||||
@@ -354,8 +354,8 @@ class MessageQueue {
|
||||
// For JSTimers to register its callback. Otherwise a circular dependency
|
||||
// between modules is introduced. Note that only one callback may be
|
||||
// registered at a time.
|
||||
setImmediatesCallback(fn: () => void) {
|
||||
this._immediatesCallback = fn;
|
||||
setReactNativeMicrotasksCallback(fn: () => void) {
|
||||
this._reactNativeMicrotasksCallback = fn;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -387,10 +387,10 @@ class MessageQueue {
|
||||
);
|
||||
}
|
||||
|
||||
__callImmediates() {
|
||||
Systrace.beginEvent('JSTimers.callImmediates()');
|
||||
if (this._immediatesCallback != null) {
|
||||
this._immediatesCallback();
|
||||
__callReactNativeMicrotasks() {
|
||||
Systrace.beginEvent('JSTimers.callReactNativeMicrotasks()');
|
||||
if (this._reactNativeMicrotasksCallback != null) {
|
||||
this._reactNativeMicrotasksCallback();
|
||||
}
|
||||
Systrace.endEvent();
|
||||
}
|
||||
@@ -409,7 +409,7 @@ class MessageQueue {
|
||||
const moduleMethods = this.getCallableModule(module);
|
||||
invariant(
|
||||
!!moduleMethods,
|
||||
`Module ${module} is not a registered callable module (calling ${method}). A frequent cause of the error is that the application entry file path is incorrect.
|
||||
`Module ${module} is not a registered callable module (calling ${method}). A frequent cause of the error is that the application entry file path is incorrect.
|
||||
This can also happen when the JS bundle is corrupt or there is an early initialization error when loading React Native.`,
|
||||
);
|
||||
invariant(
|
||||
|
||||
@@ -108,7 +108,7 @@ describe('MessageQueue', function() {
|
||||
const unknownModule = 'UnknownModule',
|
||||
unknownMethod = 'UnknownMethod';
|
||||
expect(() => queue.__callFunction(unknownModule, unknownMethod)).toThrow(
|
||||
`Module ${unknownModule} is not a registered callable module (calling ${unknownMethod}). A frequent cause of the error is that the application entry file path is incorrect.
|
||||
`Module ${unknownModule} is not a registered callable module (calling ${unknownMethod}). A frequent cause of the error is that the application entry file path is incorrect.
|
||||
This can also happen when the JS bundle is corrupt or there is an early initialization error when loading React Native.`,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -25,7 +25,7 @@ export type JSTimerType =
|
||||
| 'setTimeout'
|
||||
| 'setInterval'
|
||||
| 'requestAnimationFrame'
|
||||
| 'setImmediate'
|
||||
| 'queueReactNativeMicrotask'
|
||||
| 'requestIdleCallback';
|
||||
|
||||
// These timing constants should be kept in sync with the ones in native ios and
|
||||
@@ -37,7 +37,7 @@ const IDLE_CALLBACK_FRAME_DEADLINE = 1;
|
||||
const callbacks: Array<?Function> = [];
|
||||
const types: Array<?JSTimerType> = [];
|
||||
const timerIDs: Array<?number> = [];
|
||||
let immediates: Array<number> = [];
|
||||
let reactNativeMicrotasks: Array<number> = [];
|
||||
let requestIdleCallbacks: Array<number> = [];
|
||||
const requestIdleCallbackTimeouts: {[number]: number, ...} = {};
|
||||
|
||||
@@ -107,7 +107,7 @@ function _callTimer(timerID: number, frameTime: number, didTimeout: ?boolean) {
|
||||
if (
|
||||
type === 'setTimeout' ||
|
||||
type === 'setInterval' ||
|
||||
type === 'setImmediate'
|
||||
type === 'queueReactNativeMicrotask'
|
||||
) {
|
||||
callback();
|
||||
} else if (type === 'requestAnimationFrame') {
|
||||
@@ -143,33 +143,33 @@ function _callTimer(timerID: number, frameTime: number, didTimeout: ?boolean) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a single pass over the enqueued immediates. Returns whether
|
||||
* more immediates are queued up (can be used as a condition a while loop).
|
||||
* Performs a single pass over the enqueued reactNativeMicrotasks. Returns whether
|
||||
* more reactNativeMicrotasks are queued up (can be used as a condition a while loop).
|
||||
*/
|
||||
function _callImmediatesPass() {
|
||||
if (immediates.length === 0) {
|
||||
function _callReactNativeMicrotasksPass() {
|
||||
if (reactNativeMicrotasks.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (__DEV__) {
|
||||
Systrace.beginEvent('callImmediatesPass()');
|
||||
Systrace.beginEvent('callReactNativeMicrotasksPass()');
|
||||
}
|
||||
|
||||
// The main reason to extract a single pass is so that we can track
|
||||
// in the system trace
|
||||
const passImmediates = immediates;
|
||||
immediates = [];
|
||||
const passReactNativeMicrotasks = reactNativeMicrotasks;
|
||||
reactNativeMicrotasks = [];
|
||||
|
||||
// Use for loop rather than forEach as per @vjeux's advice
|
||||
// https://github.com/facebook/react-native/commit/c8fd9f7588ad02d2293cac7224715f4af7b0f352#commitcomment-14570051
|
||||
for (let i = 0; i < passImmediates.length; ++i) {
|
||||
_callTimer(passImmediates[i], 0);
|
||||
for (let i = 0; i < passReactNativeMicrotasks.length; ++i) {
|
||||
_callTimer(passReactNativeMicrotasks[i], 0);
|
||||
}
|
||||
|
||||
if (__DEV__) {
|
||||
Systrace.endEvent();
|
||||
}
|
||||
return immediates.length > 0;
|
||||
return reactNativeMicrotasks.length > 0;
|
||||
}
|
||||
|
||||
function _clearIndex(i: number) {
|
||||
@@ -190,7 +190,10 @@ function _freeCallback(timerID: number) {
|
||||
if (index !== -1) {
|
||||
const type = types[index];
|
||||
_clearIndex(index);
|
||||
if (type !== 'setImmediate' && type !== 'requestIdleCallback') {
|
||||
if (
|
||||
type !== 'queueReactNativeMicrotask' &&
|
||||
type !== 'requestIdleCallback'
|
||||
) {
|
||||
deleteTimer(timerID);
|
||||
}
|
||||
}
|
||||
@@ -233,15 +236,19 @@ const JSTimers = {
|
||||
},
|
||||
|
||||
/**
|
||||
* The React Native microtask mechanism is used to back public APIs e.g.
|
||||
* `queueMicrotask`, `clearImmediate`, and `setImmediate` (which is used by
|
||||
* the Promise polyfill) when the JSVM microtask mechanism is not used.
|
||||
*
|
||||
* @param {function} func Callback to be invoked before the end of the
|
||||
* current JavaScript execution loop.
|
||||
*/
|
||||
setImmediate: function(func: Function, ...args: any) {
|
||||
queueReactNativeMicrotask: function(func: Function, ...args: any) {
|
||||
const id = _allocateCallback(
|
||||
() => func.apply(undefined, args),
|
||||
'setImmediate',
|
||||
'queueReactNativeMicrotask',
|
||||
);
|
||||
immediates.push(id);
|
||||
reactNativeMicrotasks.push(id);
|
||||
return id;
|
||||
},
|
||||
|
||||
@@ -323,11 +330,11 @@ const JSTimers = {
|
||||
_freeCallback(timerID);
|
||||
},
|
||||
|
||||
clearImmediate: function(timerID: number) {
|
||||
clearReactNativeMicrotask: function(timerID: number) {
|
||||
_freeCallback(timerID);
|
||||
const index = immediates.indexOf(timerID);
|
||||
const index = reactNativeMicrotasks.indexOf(timerID);
|
||||
if (index !== -1) {
|
||||
immediates.splice(index, 1);
|
||||
reactNativeMicrotasks.splice(index, 1);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -406,9 +413,9 @@ const JSTimers = {
|
||||
* This is called after we execute any command we receive from native but
|
||||
* before we hand control back to native.
|
||||
*/
|
||||
callImmediates() {
|
||||
callReactNativeMicrotasks() {
|
||||
errors = (null: ?Array<Error>);
|
||||
while (_callImmediatesPass()) {}
|
||||
while (_callReactNativeMicrotasksPass()) {}
|
||||
if (errors) {
|
||||
errors.forEach(error =>
|
||||
JSTimers.setTimeout(() => {
|
||||
@@ -452,17 +459,17 @@ function setSendIdleEvents(sendIdleEvents: boolean): void {
|
||||
|
||||
let ExportedJSTimers: {|
|
||||
callIdleCallbacks: (frameTime: number) => any | void,
|
||||
callImmediates: () => void,
|
||||
callReactNativeMicrotasks: () => void,
|
||||
callTimers: (timersToCall: Array<number>) => any | void,
|
||||
cancelAnimationFrame: (timerID: number) => void,
|
||||
cancelIdleCallback: (timerID: number) => void,
|
||||
clearImmediate: (timerID: number) => void,
|
||||
clearReactNativeMicrotask: (timerID: number) => void,
|
||||
clearInterval: (timerID: number) => void,
|
||||
clearTimeout: (timerID: number) => void,
|
||||
emitTimeDriftWarning: (warningMessage: string) => any | void,
|
||||
requestAnimationFrame: (func: any) => any | number,
|
||||
requestIdleCallback: (func: any, options: ?any) => any | number,
|
||||
setImmediate: (func: any, ...args: any) => number,
|
||||
queueReactNativeMicrotask: (func: any, ...args: any) => number,
|
||||
setInterval: (func: any, duration: number, ...args: any) => number,
|
||||
setTimeout: (func: any, duration: number, ...args: any) => number,
|
||||
|};
|
||||
@@ -471,13 +478,15 @@ if (!NativeTiming) {
|
||||
console.warn("Timing native module is not available, can't set timers.");
|
||||
// $FlowFixMe[prop-missing] : we can assume timers are generally available
|
||||
ExportedJSTimers = ({
|
||||
callImmediates: JSTimers.callImmediates,
|
||||
setImmediate: JSTimers.setImmediate,
|
||||
callReactNativeMicrotasks: JSTimers.callReactNativeMicrotasks,
|
||||
queueReactNativeMicrotask: JSTimers.queueReactNativeMicrotask,
|
||||
}: typeof JSTimers);
|
||||
} else {
|
||||
ExportedJSTimers = JSTimers;
|
||||
}
|
||||
|
||||
BatchedBridge.setImmediatesCallback(JSTimers.callImmediates);
|
||||
BatchedBridge.setReactNativeMicrotasksCallback(
|
||||
JSTimers.callReactNativeMicrotasks,
|
||||
);
|
||||
|
||||
module.exports = ExportedJSTimers;
|
||||
|
||||
@@ -65,15 +65,15 @@ describe('JSTimers', function() {
|
||||
expect(callCount).toBe(1);
|
||||
});
|
||||
|
||||
it('should call nested setImmediate when cleared', function() {
|
||||
it('should call nested queueReactNativeMicrotask when cleared', function() {
|
||||
let id1, id2, id3;
|
||||
let callCount = 0;
|
||||
|
||||
id1 = JSTimers.setImmediate(function() {
|
||||
JSTimers.clearImmediate(id1);
|
||||
id2 = JSTimers.setImmediate(function() {
|
||||
JSTimers.clearImmediate(id2);
|
||||
id3 = JSTimers.setImmediate(function() {
|
||||
id1 = JSTimers.queueReactNativeMicrotask(function() {
|
||||
JSTimers.clearReactNativeMicrotask(id1);
|
||||
id2 = JSTimers.queueReactNativeMicrotask(function() {
|
||||
JSTimers.clearReactNativeMicrotask(id2);
|
||||
id3 = JSTimers.queueReactNativeMicrotask(function() {
|
||||
callCount += 1;
|
||||
});
|
||||
});
|
||||
@@ -132,64 +132,64 @@ describe('JSTimers', function() {
|
||||
expect(callback).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should call function with setImmediate', function() {
|
||||
it('should call function with queueReactNativeMicrotask', function() {
|
||||
const callback = jest.fn();
|
||||
JSTimers.setImmediate(callback);
|
||||
JSTimers.callImmediates();
|
||||
JSTimers.queueReactNativeMicrotask(callback);
|
||||
JSTimers.callReactNativeMicrotasks();
|
||||
expect(callback).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should not call function with clearImmediate', function() {
|
||||
it('should not call function with clearReactNativeMicrotask', function() {
|
||||
const callback = jest.fn();
|
||||
const id = JSTimers.setImmediate(callback);
|
||||
JSTimers.clearImmediate(id);
|
||||
JSTimers.callImmediates();
|
||||
const id = JSTimers.queueReactNativeMicrotask(callback);
|
||||
JSTimers.clearReactNativeMicrotask(id);
|
||||
JSTimers.callReactNativeMicrotasks();
|
||||
expect(callback).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('should call functions in the right order with setImmediate', function() {
|
||||
it('should call functions in the right order with queueReactNativeMicrotask', function() {
|
||||
let count = 0;
|
||||
let firstCalled = null;
|
||||
let secondCalled = null;
|
||||
JSTimers.setImmediate(function() {
|
||||
JSTimers.queueReactNativeMicrotask(function() {
|
||||
firstCalled = count++;
|
||||
});
|
||||
JSTimers.setImmediate(function() {
|
||||
JSTimers.queueReactNativeMicrotask(function() {
|
||||
secondCalled = count++;
|
||||
});
|
||||
JSTimers.callImmediates();
|
||||
JSTimers.callReactNativeMicrotasks();
|
||||
expect(firstCalled).toBe(0);
|
||||
expect(secondCalled).toBe(1);
|
||||
});
|
||||
|
||||
it('should call functions in the right order with nested setImmediate', function() {
|
||||
it('should call functions in the right order with nested queueReactNativeMicrotask', function() {
|
||||
let count = 0;
|
||||
let firstCalled = null;
|
||||
let secondCalled = null;
|
||||
let thirdCalled = null;
|
||||
JSTimers.setImmediate(function() {
|
||||
JSTimers.queueReactNativeMicrotask(function() {
|
||||
firstCalled = count++;
|
||||
JSTimers.setImmediate(function() {
|
||||
JSTimers.queueReactNativeMicrotask(function() {
|
||||
thirdCalled = count++;
|
||||
});
|
||||
secondCalled = count++;
|
||||
});
|
||||
JSTimers.callImmediates();
|
||||
JSTimers.callReactNativeMicrotasks();
|
||||
expect(firstCalled).toBe(0);
|
||||
expect(secondCalled).toBe(1);
|
||||
expect(thirdCalled).toBe(2);
|
||||
});
|
||||
|
||||
it('should call nested setImmediate', function() {
|
||||
it('should call nested queueReactNativeMicrotask', function() {
|
||||
let firstCalled = false;
|
||||
let secondCalled = false;
|
||||
JSTimers.setImmediate(function() {
|
||||
JSTimers.queueReactNativeMicrotask(function() {
|
||||
firstCalled = true;
|
||||
JSTimers.setImmediate(function() {
|
||||
JSTimers.queueReactNativeMicrotask(function() {
|
||||
secondCalled = true;
|
||||
});
|
||||
});
|
||||
JSTimers.callImmediates();
|
||||
JSTimers.callReactNativeMicrotasks();
|
||||
expect(firstCalled).toBe(true);
|
||||
expect(secondCalled).toBe(true);
|
||||
});
|
||||
@@ -319,34 +319,34 @@ describe('JSTimers', function() {
|
||||
);
|
||||
});
|
||||
|
||||
it('should pass along errors thrown from setImmediate', function() {
|
||||
JSTimers.setImmediate(function() {
|
||||
throw new Error('error within setImmediate');
|
||||
it('should pass along errors thrown from queueReactNativeMicrotask', function() {
|
||||
JSTimers.queueReactNativeMicrotask(function() {
|
||||
throw new Error('error within queueReactNativeMicrotask');
|
||||
});
|
||||
|
||||
NativeTiming.createTimer = jest.fn();
|
||||
JSTimers.callImmediates();
|
||||
JSTimers.callReactNativeMicrotasks();
|
||||
|
||||
// The remaining errors should be called within setTimeout, in case there
|
||||
// are a series of them
|
||||
expect(NativeTiming.createTimer).toBeCalled();
|
||||
const timerID = NativeTiming.createTimer.mock.calls[0][0];
|
||||
expect(JSTimers.callTimers.bind(null, [timerID])).toThrowError(
|
||||
'error within setImmediate',
|
||||
'error within queueReactNativeMicrotask',
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw all errors from setImmediate', function() {
|
||||
JSTimers.setImmediate(function() {
|
||||
it('should throw all errors from queueReactNativeMicrotask', function() {
|
||||
JSTimers.queueReactNativeMicrotask(function() {
|
||||
throw new Error('first error');
|
||||
});
|
||||
|
||||
JSTimers.setImmediate(function() {
|
||||
JSTimers.queueReactNativeMicrotask(function() {
|
||||
throw new Error('second error');
|
||||
});
|
||||
|
||||
NativeTiming.createTimer = jest.fn();
|
||||
JSTimers.callImmediates();
|
||||
JSTimers.callReactNativeMicrotasks();
|
||||
|
||||
expect(NativeTiming.createTimer.mock.calls.length).toBe(2);
|
||||
|
||||
|
||||
@@ -22,13 +22,23 @@ if (!global.RN$Bridgeless) {
|
||||
polyfillGlobal(name, () => require('./Timers/JSTimers')[name]);
|
||||
};
|
||||
defineLazyTimer('setTimeout');
|
||||
defineLazyTimer('setInterval');
|
||||
defineLazyTimer('setImmediate');
|
||||
defineLazyTimer('clearTimeout');
|
||||
defineLazyTimer('setInterval');
|
||||
defineLazyTimer('clearInterval');
|
||||
defineLazyTimer('clearImmediate');
|
||||
defineLazyTimer('requestAnimationFrame');
|
||||
defineLazyTimer('cancelAnimationFrame');
|
||||
defineLazyTimer('requestIdleCallback');
|
||||
defineLazyTimer('cancelIdleCallback');
|
||||
|
||||
/**
|
||||
* Set up immediate APIs as aliases to the ReactNativeMicrotask APIs.
|
||||
*/
|
||||
polyfillGlobal(
|
||||
'setImmediate',
|
||||
() => require('./Timers/JSTimers').queueReactNativeMicrotask,
|
||||
);
|
||||
polyfillGlobal(
|
||||
'clearImmediate',
|
||||
() => require('./Timers/JSTimers').clearReactNativeMicrotask,
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user