function _callTimer(timerID: number, frameTime: number, didTimeout: ?boolean) {
  /* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an
   * error found when Flow v0.54 was deployed. To see the error delete this
   * comment and run Flow. */
  require('fbjs/lib/warning')(
    timerID <= GUID,
    'Tried to call timer with ID %s but no such timer exists.',
    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.
  const timerIndex = timerIDs.indexOf(timerID);
  if (timerIndex === -1) {
    return;
  }

  const type = types[timerIndex];
  const callback = callbacks[timerIndex];
  if (!callback || !type) {
    console.error('No callback found for timerID ' + timerID);
    return;
  }

  if (__DEV__) {
    const identifier = identifiers[timerIndex] || {};
    Systrace.beginEvent('Systrace.callTimer: ' + identifier.methodName);
  }

  // Clear the metadata
  if (
    type === 'setTimeout' ||
    type === 'setImmediate' ||
    type === 'requestAnimationFrame' ||
    type === 'requestIdleCallback'
  ) {
    _clearIndex(timerIndex);
  }

  try {
    if (
      type === 'setTimeout' ||
      type === 'setInterval' ||
      type === 'setImmediate'
    ) {
      callback();
    } else if (type === 'requestAnimationFrame') {
      callback(performanceNow());
    } else if (type === 'requestIdleCallback') {
      callback({
        timeRemaining: function() {
          // TODO: Optimisation: allow running for longer than one frame if
          // there are no pending JS calls on the bridge from native. This
          // would require a way to check the bridge queue synchronously.
          return Math.max(0, FRAME_DURATION - (performanceNow() - frameTime));
        },
        didTimeout: !!didTimeout,
      });
    } else {
      console.error('Tried to call a callback with invalid type: ' + type);
    }
  } catch (e) {
    // Don't rethrow so that we can run all timers.
    if (!errors) {
      errors = [e];
    } else {
      errors.push(e);
    }
  }

  if (__DEV__) {
    Systrace.endEvent();
  }
}
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).