Зная время происхождения метки времени события - PullRequest
0 голосов
/ 30 июня 2018

Недавно некоторые браузеры начали использовать Высокое разрешение отметки времени для своих событий . Одно из основных отличий от предыдущего подхода заключается в том, что эта длительность относится не к эпохе системы, а к некоторому «источнику времени» (большую часть времени примерно в момент загрузки документа).

Проблема в том, что я не могу найти какой-либо надежный способ проверить, использует ли браузер метки времени высокого разрешения или предыдущий подход.

Это не проблема, если сравнивать только временные метки события, но если кто-то хочет сравнить временные метки события с ручными метками времени, нужно знать, должен ли он использовать Date.now() (относительно эпохи) или precision.now() (относительно время происхождения).

Например, хотя safari mobile поддерживает API производительности, некоторые версии (например, в iOS 11.1) еще не переключили свои события на отметки времени с высоким разрешением. В результате следующий фрагмент дает бессмысленно огромные значения для 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;
}
<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>

Снимок экрана с iPad (iOS 11.1): enter image description here

Ответы [ 2 ]

0 голосов
/ 30 июня 2018

В итоге я изменил решение, извлеченное из Маджида Валипура . Идея на самом деле очень похожа на 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>
0 голосов
/ 30 июня 2018

Предполагая, что браузер последовательно использует один и тот же механизм для всех временных отметок, я предлагаю просто вызвать фиктивное событие, чтобы сделать тест заранее:

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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...