129 lines
3.9 KiB
JavaScript
129 lines
3.9 KiB
JavaScript
/**
|
|
* 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;
|