react-native/Libraries/JavaScriptAppEngine/System/JSTimers/JSTimers.js

141 lines
4.5 KiB
JavaScript

/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @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 RCTTiming = require('NativeModules').Timing;
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;
RCTTiming.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;
RCTTiming.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;
RCTTiming.createTimer(newID, 1, 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) {
RCTTiming.deleteTimer(timerID);
}
}
},
};
module.exports = JSTimers;