了解事件时间戳的时间来源

时间:2018-06-29 23:10:43

标签: javascript dom-events high-resolution-time

最近some browsers开始将High Resolution time stamps用作他们的events。与以前的方法的主要区别之一是该持续时间不是相对于系统时代,而是相对于some "time origin"(大多数时间大约是文档加载的时间)。

问题是我找不到任何可靠的方法来检查浏览器是否使用高分辨率时间戳或以前的方法。

如果仅比较事件时间戳,这不是问题,但是如果要比较事件时间戳和手工时间戳,则需要知道他应该使用Date.now()(相对于纪元)还是{{1} }(相对于时间原点)。

例如,尽管safari mobile支持性能api,但某些版本(例如,iOS 11.1中的版本)尚未将其事件切换为“高分辨率时间戳”。 结果,以下代码段为precision.now()产生了无意义的巨大值,因为difference结束时是高分辨率时间戳,而不是事件的时间戳。

start
const now = performance ? () => performance.now() : () => Date.now();

let start;

const update = e => {
  if(e) e.preventDefault();
  document.querySelector('#start').innerHTML = start;
  document.querySelector('#event').innerHTML = e ? e.timeStamp : '';
  document.querySelector('#diff').innerHTML = e ? e.timeStamp - start : '';
};

const reset = () => {
  start = now();
  update();
}

reset();

document.querySelector('#reset').addEventListener('click', reset);
document.querySelector('#pad').addEventListener('mousemove', update);
document.querySelector('#pad').addEventListener('touchmove', update);
#pad {
  background-color: #C9DBFA;
  border: 1px solid #778294;
  border-radius: 10px;
  width: 500px;
  height: 100px;
  color: #575E6C;
  padding: .5em .75em;
}

#reset {
  margin: 1em 0;
}

来自iPad(iOS 11.1)的屏幕截图: enter image description here

2 个答案:

答案 0 :(得分:1)

假设浏览器在所有时间戳上一致地使用相同的机制,我建议简单地触发一个虚拟事件以预先进行测试:

var isPerformanceTimestamp = false;
if (performance) {
    var performanceNow = performance.now();
    document.addEventListener('test-performance', function(evt) {
        isPerformanceTimestamp = evt.timeStamp - performanceNow < 1000; // or whatever threshold you feel comfortable with, it's at least 1530355731395 at the time of this writing ;-)
        document.removeEventListener('test-performance', this);
    });
    var event = new Event('test-performance');
    document.dispatchEvent(event);
}

答案 1 :(得分:0)

我最终修改了从Majid Valipour's tool中提取的解决方案。这个想法实际上与digitalbreed's非常相似,但有更多的保护措施:

const context = global || window || self;

const doEventUseHighResTimeStamps = () => {
  // If the performance API isn't even available, I assume events will not
  // use high res time stamps.
  if ('performance' in context) return false;

  // Check if the browser supports CustomEvents.
  const hasCustomEvent =
    'CustomEvent' in context &&
    (typeof context.CustomEvent === 'function' ||
      context.CustomEvent.toString().indexOf('CustomEventConstructor') > -1);

  // Create an event and compare its timestamps to the value returned by
  // performance.now(). If the event is using old timestamps, its origin
  // is going to be very far and hence, its timestamps will be much much
  // greater than performance.now().
  const testTimeStamp = hasCustomEvent
    ? new context.CustomEvent('test').timeStamp
    : context.document.createEvent('KeyboardEvent').timeStamp;
  return testTimeStamp && testTimeStamp <= performance.now();
};

const context = window;

const doEventUseHighResTimeStamps = () => {
  const hasCustomEvent =
    'CustomEvent' in context &&
    (typeof context.CustomEvent === 'function' ||
      context.CustomEvent.toString().indexOf('CustomEventConstructor') > -1);

  const testTimeStamp = hasCustomEvent
    ? new context.CustomEvent('test').timeStamp
    : context.document.createEvent('KeyboardEvent').timeStamp;
  return testTimeStamp && testTimeStamp <= performance.now();
};

const now = doEventUseHighResTimeStamps() ? () => performance.now() : () => Date.now();

let start;

const update = e => {
  if (e) e.preventDefault();
  document.querySelector('#start').innerHTML = start;
  document.querySelector('#event').innerHTML = e ? e.timeStamp : '';
  document.querySelector('#diff').innerHTML = e ? e.timeStamp - start : '';
};

const reset = () => {
  start = now();
  update();
}

reset();

document.querySelector('#reset').addEventListener('click', reset);
document.querySelector('#pad').addEventListener('mousemove', update);
document.querySelector('#pad').addEventListener('touchmove', update);
#pad {
  background-color: #C9DBFA;
  border: 1px solid #778294;
  border-radius: 10px;
  width: 500px;
  height: 100px;
  color: #575E6C;
  padding: .5em .75em;
}

#reset {
  margin: 1em 0;
}
<div id="pad">
  <strong>start time:</strong> <span id="start"></span>
  <br/>
  <strong>event time:</strong> <span id="event"></span>
  <br/>
  <strong>difference:</strong> <span id="diff"></span>
</div>
<button id="reset">reset</button>