mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-01-31 09:08:48 +08:00
Initial commit
This commit is contained in:
135
Libraries/JavaScriptAppEngine/System/JSTimers/JSTimers.js
Normal file
135
Libraries/JavaScriptAppEngine/System/JSTimers/JSTimers.js
Normal file
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule JSTimers
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
// Note that the module JSTimers is split into two in order to solve a cycle
|
||||
// in dependencies. NativeModules > BatchedBridge > MessageQueue > JSTimersExecution
|
||||
var RKTiming = require('NativeModules').RKTiming;
|
||||
var JSTimersExecution = require('JSTimersExecution');
|
||||
|
||||
/**
|
||||
* JS implementation of timer functions. Must be completely driven by an
|
||||
* external clock signal, all that's stored here is timerID, timer type, and
|
||||
* callback.
|
||||
*/
|
||||
var JSTimers = {
|
||||
Types: JSTimersExecution.Types,
|
||||
|
||||
/**
|
||||
* Returns a free index if one is available, and the next consecutive index
|
||||
* otherwise.
|
||||
*/
|
||||
_getFreeIndex: function() {
|
||||
var freeIndex = JSTimersExecution.timerIDs.indexOf(null);
|
||||
if (freeIndex === -1) {
|
||||
freeIndex = JSTimersExecution.timerIDs.length;
|
||||
}
|
||||
return freeIndex;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {function} func Callback to be invoked after `duration` ms.
|
||||
* @param {number} duration Number of milliseconds.
|
||||
*/
|
||||
setTimeout: function(func, duration, ...args) {
|
||||
var newID = JSTimersExecution.GUID++;
|
||||
var freeIndex = JSTimers._getFreeIndex();
|
||||
JSTimersExecution.timerIDs[freeIndex] = newID;
|
||||
JSTimersExecution.callbacks[freeIndex] = func;
|
||||
JSTimersExecution.callbacks[freeIndex] = function() {
|
||||
return func.apply(undefined, args);
|
||||
};
|
||||
JSTimersExecution.types[freeIndex] = JSTimersExecution.Type.setTimeout;
|
||||
RKTiming.createTimer(newID, duration, Date.now(), /** recurring */ false);
|
||||
return newID;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {function} func Callback to be invoked every `duration` ms.
|
||||
* @param {number} duration Number of milliseconds.
|
||||
*/
|
||||
setInterval: function(func, duration, ...args) {
|
||||
var newID = JSTimersExecution.GUID++;
|
||||
var freeIndex = JSTimers._getFreeIndex();
|
||||
JSTimersExecution.timerIDs[freeIndex] = newID;
|
||||
JSTimersExecution.callbacks[freeIndex] = func;
|
||||
JSTimersExecution.callbacks[freeIndex] = function() {
|
||||
return func.apply(undefined, args);
|
||||
};
|
||||
JSTimersExecution.types[freeIndex] = JSTimersExecution.Type.setInterval;
|
||||
RKTiming.createTimer(newID, duration, Date.now(), /** recurring */ true);
|
||||
return newID;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {function} func Callback to be invoked before the end of the
|
||||
* current JavaScript execution loop.
|
||||
*/
|
||||
setImmediate: function(func, ...args) {
|
||||
var newID = JSTimersExecution.GUID++;
|
||||
var freeIndex = JSTimers._getFreeIndex();
|
||||
JSTimersExecution.timerIDs[freeIndex] = newID;
|
||||
JSTimersExecution.callbacks[freeIndex] = func;
|
||||
JSTimersExecution.callbacks[freeIndex] = function() {
|
||||
return func.apply(undefined, args);
|
||||
};
|
||||
JSTimersExecution.types[freeIndex] = JSTimersExecution.Type.setImmediate;
|
||||
JSTimersExecution.immediates.push(newID);
|
||||
return newID;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {function} func Callback to be invoked every frame.
|
||||
*/
|
||||
requestAnimationFrame: function(func) {
|
||||
var newID = JSTimersExecution.GUID++;
|
||||
var freeIndex = JSTimers._getFreeIndex();
|
||||
JSTimersExecution.timerIDs[freeIndex] = newID;
|
||||
JSTimersExecution.callbacks[freeIndex] = func;
|
||||
JSTimersExecution.types[freeIndex] = JSTimersExecution.Type.requestAnimationFrame;
|
||||
RKTiming.createTimer(newID, 0, Date.now(), /** recurring */ false);
|
||||
return newID;
|
||||
},
|
||||
|
||||
clearTimeout: function(timerID) {
|
||||
JSTimers._clearTimerID(timerID);
|
||||
},
|
||||
|
||||
clearInterval: function(timerID) {
|
||||
JSTimers._clearTimerID(timerID);
|
||||
},
|
||||
|
||||
clearImmediate: function(timerID) {
|
||||
JSTimers._clearTimerID(timerID);
|
||||
JSTimersExecution.immediates.splice(
|
||||
JSTimersExecution.immediates.indexOf(timerID),
|
||||
1
|
||||
);
|
||||
},
|
||||
|
||||
cancelAnimationFrame: function(timerID) {
|
||||
JSTimers._clearTimerID(timerID);
|
||||
},
|
||||
|
||||
_clearTimerID: function(timerID) {
|
||||
// JSTimersExecution.timerIDs contains nulls after timers have been removed;
|
||||
// ignore nulls upfront so indexOf doesn't find them
|
||||
if (timerID == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var index = JSTimersExecution.timerIDs.indexOf(timerID);
|
||||
// See corresponding comment in `callTimers` for reasoning behind this
|
||||
if (index !== -1) {
|
||||
JSTimersExecution._clearIndex(index);
|
||||
if (JSTimersExecution.types[index] !== JSTimersExecution.Type.setImmediate) {
|
||||
RKTiming.deleteTimer(timerID);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = JSTimers;
|
||||
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule JSTimersExecution
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var invariant = require('invariant');
|
||||
var keyMirror = require('keyMirror');
|
||||
var performanceNow = require('performanceNow');
|
||||
var warning = require('warning');
|
||||
|
||||
/**
|
||||
* JS implementation of timer functions. Must be completely driven by an
|
||||
* external clock signal, all that's stored here is timerID, timer type, and
|
||||
* callback.
|
||||
*/
|
||||
var JSTimersExecution = {
|
||||
GUID: 1,
|
||||
Type: keyMirror({
|
||||
setTimeout: null,
|
||||
setInterval: null,
|
||||
requestAnimationFrame: null,
|
||||
setImmediate: null,
|
||||
}),
|
||||
|
||||
// Parallel arrays:
|
||||
callbacks: [],
|
||||
types: [],
|
||||
timerIDs: [],
|
||||
immediates: [],
|
||||
|
||||
/**
|
||||
* Calls the callback associated with the ID. Also unregister that callback
|
||||
* if it was a one time timer (setTimeout), and not unregister it if it was
|
||||
* recurring (setInterval).
|
||||
*/
|
||||
callTimer: function(timerID) {
|
||||
warning(timerID <= JSTimersExecution.GUID, 'Tried to call timer with ID ' + timerID + ' but no such timer exists');
|
||||
var timerIndex = JSTimersExecution.timerIDs.indexOf(timerID);
|
||||
// timerIndex of -1 means that no timer with that ID exists. There are
|
||||
// two situations when this happens, when a garbage timer ID was given
|
||||
// and when a previously existing timer was deleted before this callback
|
||||
// fired. In both cases we want to ignore the timer id, but in the former
|
||||
// case we warn as well.
|
||||
if (timerIndex === -1) {
|
||||
return;
|
||||
}
|
||||
var type = JSTimersExecution.types[timerIndex];
|
||||
var callback = JSTimersExecution.callbacks[timerIndex];
|
||||
|
||||
// Clear the metadata
|
||||
if (type === JSTimersExecution.Type.setTimeout ||
|
||||
type === JSTimersExecution.Type.setImmediate ||
|
||||
type === JSTimersExecution.Type.requestAnimationFrame) {
|
||||
JSTimersExecution._clearIndex(timerIndex);
|
||||
}
|
||||
|
||||
try {
|
||||
if (type === JSTimersExecution.Type.setTimeout ||
|
||||
type === JSTimersExecution.Type.setInterval ||
|
||||
type === JSTimersExecution.Type.setImmediate) {
|
||||
callback();
|
||||
} else if (type === JSTimersExecution.Type.requestAnimationFrame) {
|
||||
var currentTime = performanceNow();
|
||||
callback(currentTime);
|
||||
} else {
|
||||
console.error('Tried to call a callback with invalid type: ' + type);
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
// Don't rethrow so that we can run every other timer.
|
||||
JSTimersExecution.errors = JSTimersExecution.errors || [];
|
||||
JSTimersExecution.errors.push(e);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This is called from the native side. We are passed an array of timerIDs,
|
||||
* and
|
||||
*/
|
||||
callTimers: function(timerIDs) {
|
||||
invariant(timerIDs.length !== 0, 'Probably shouldn\'t call "callTimers" with no timerIDs');
|
||||
|
||||
JSTimersExecution.errors = null;
|
||||
timerIDs.forEach(JSTimersExecution.callTimer);
|
||||
|
||||
var errors = JSTimersExecution.errors;
|
||||
if (errors) {
|
||||
var errorCount = errors.length;
|
||||
if (errorCount > 1) {
|
||||
// Throw all the other errors in a setTimeout, which will throw each
|
||||
// error one at a time
|
||||
for (var ii = 1; ii < errorCount; ii++) {
|
||||
require('JSTimers').setTimeout(
|
||||
((error) => { throw error; }).bind(null, errors[ii]),
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
||||
throw errors[0];
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This is called after we execute any command we receive from native but
|
||||
* before we hand control back to native.
|
||||
*/
|
||||
callImmediates: function() {
|
||||
JSTimersExecution.errors = null;
|
||||
while (JSTimersExecution.immediates.length !== 0) {
|
||||
JSTimersExecution.callTimer(JSTimersExecution.immediates.shift());
|
||||
}
|
||||
if (JSTimersExecution.errors) {
|
||||
JSTimersExecution.errors.forEach((error) =>
|
||||
require('JSTimers').setTimeout(() => { throw error; }, 0)
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
_clearIndex: function(i) {
|
||||
JSTimersExecution.timerIDs[i] = null;
|
||||
JSTimersExecution.callbacks[i] = null;
|
||||
JSTimersExecution.types[i] = null;
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = JSTimersExecution;
|
||||
Reference in New Issue
Block a user