2015-01-30 01:10:49 +00:00
|
|
|
/**
|
2015-03-23 22:07:33 +00:00
|
|
|
* 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.
|
2015-01-30 01:10:49 +00:00
|
|
|
*
|
|
|
|
* @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
|
2015-03-18 22:57:49 +00:00
|
|
|
var RCTTiming = require('NativeModules').Timing;
|
2015-01-30 01:10:49 +00:00
|
|
|
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] = function() {
|
|
|
|
return func.apply(undefined, args);
|
|
|
|
};
|
|
|
|
JSTimersExecution.types[freeIndex] = JSTimersExecution.Type.setTimeout;
|
2015-08-01 08:44:05 +00:00
|
|
|
RCTTiming.createTimer(newID, duration || 0, Date.now(), /** recurring */ false);
|
2015-01-30 01:10:49 +00:00
|
|
|
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] = function() {
|
2015-05-31 18:30:27 +00:00
|
|
|
return func.apply(undefined, args);
|
2015-01-30 01:10:49 +00:00
|
|
|
};
|
|
|
|
JSTimersExecution.types[freeIndex] = JSTimersExecution.Type.setInterval;
|
2015-08-01 08:44:05 +00:00
|
|
|
RCTTiming.createTimer(newID, duration || 0, Date.now(), /** recurring */ true);
|
2015-01-30 01:10:49 +00:00
|
|
|
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] = 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;
|
2015-03-18 22:57:49 +00:00
|
|
|
RCTTiming.createTimer(newID, 1, Date.now(), /** recurring */ false);
|
2015-01-30 01:10:49 +00:00
|
|
|
return newID;
|
|
|
|
},
|
|
|
|
|
2016-07-14 01:43:27 +00:00
|
|
|
/**
|
|
|
|
* @param {function} func Callback to be invoked every frame and provided
|
|
|
|
* with time remaining in frame.
|
|
|
|
*/
|
|
|
|
requestIdleCallback: function(func) {
|
|
|
|
if (JSTimersExecution.requestIdleCallbacks.length === 0) {
|
|
|
|
RCTTiming.setSendIdleEvents(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
var newID = JSTimersExecution.GUID++;
|
|
|
|
var freeIndex = JSTimers._getFreeIndex();
|
|
|
|
JSTimersExecution.timerIDs[freeIndex] = newID;
|
|
|
|
JSTimersExecution.callbacks[freeIndex] = func;
|
|
|
|
JSTimersExecution.types[freeIndex] = JSTimersExecution.Type.requestIdleCallback;
|
|
|
|
JSTimersExecution.requestIdleCallbacks.push(newID);
|
|
|
|
return newID;
|
|
|
|
},
|
|
|
|
|
|
|
|
cancelIdleCallback: function(timerID) {
|
|
|
|
JSTimers._clearTimerID(timerID);
|
|
|
|
var index = JSTimersExecution.requestIdleCallbacks.indexOf(timerID);
|
|
|
|
if (index !== -1) {
|
|
|
|
JSTimersExecution.requestIdleCallbacks.splice(index, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (JSTimersExecution.requestIdleCallbacks.length === 0) {
|
|
|
|
RCTTiming.setSendIdleEvents(false);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2015-01-30 01:10:49 +00:00
|
|
|
clearTimeout: function(timerID) {
|
|
|
|
JSTimers._clearTimerID(timerID);
|
|
|
|
},
|
|
|
|
|
|
|
|
clearInterval: function(timerID) {
|
|
|
|
JSTimers._clearTimerID(timerID);
|
|
|
|
},
|
|
|
|
|
|
|
|
clearImmediate: function(timerID) {
|
|
|
|
JSTimers._clearTimerID(timerID);
|
2016-02-28 19:40:50 +00:00
|
|
|
var index = JSTimersExecution.immediates.indexOf(timerID);
|
|
|
|
if (index !== -1) {
|
|
|
|
JSTimersExecution.immediates.splice(index, 1);
|
|
|
|
}
|
2015-01-30 01:10:49 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
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);
|
2016-07-14 01:43:27 +00:00
|
|
|
var type = JSTimersExecution.types[index];
|
|
|
|
if (type !== JSTimersExecution.Type.setImmediate &&
|
|
|
|
type !== JSTimersExecution.Type.requestIdleCallback) {
|
2015-03-17 20:42:44 +00:00
|
|
|
RCTTiming.deleteTimer(timerID);
|
2015-01-30 01:10:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
module.exports = JSTimers;
|