Javascript 中浏览器事件的时间戳来自哪里?

Where does a browser event's timeStamp come from in Javascript?

传递给事件处理程序回调的事件对象包含事件发生时间的 event.timeStamp,但时间戳是在哪里产生的?它是从底层 OS 冒出来的东西,还是由浏览器生成的?

我对衡量时间戳的可靠性很感兴趣,并且认识到生成的时间戳越晚,它的准确性就越低。

此外,生成时间戳的方式在平台和浏览器实现之间是否有很大差异?

谢谢。

根据DOM4 specification §4.2,它是在创建事件时分配的(您必须向下滚动一点):

The timeStamp attribute must return the value it was initialized to. When an event is created the attribute must be initialized to the number of milliseconds that have passed since 00:00:00 UTC on 1 January 1970, ignoring leap seconds.

这引出了一个问题:事件是什么时候创建的?我可以想到三遍它可能会完成:

  1. 当OS通知浏览器时

  2. 当 JavaScript 主 UI 线程接下来可以做 任何事情

  3. 当JavaScript主UI线程即将派发与事件相关的任务时

使用下面的代码片段,至少对于 click 事件,它似乎因浏览器而异:

  • Chrome 似乎在 JavaScript 主 UI 线程准备好时分配 timeStamp handle 事件(上面#3);这可能发生在事件实际发生之后,即使主 JavaScript UI 线程在此期间有机会做其他事情。 (对我来说,这非常令人惊讶。) (2019 年 9 月更新:Chrome 似乎不再这样做了。)

  • Chrome 和 Firefox 似乎在事件发生时分配 timeStamp(上面的#1),无论主要 JavaScript UI 线程正在做。这是我所期望的。

  • IE 似乎 在 JavaScript 主 UI 线程准备好时分配 timeStamp 处理事件(上面#3);这可能发生在事件实际发生之后,即使主 JavaScript UI 线程在此期间有机会做其他事情。但我不能排除它会在处理第二次点击时为第三次点击分配时间戳的可能性(#2),因为当事情很忙时我无法让它识别第三个按钮上的点击。

// Sadly, Firefox has a bug (https://bugzilla.mozilla.org/show_bug.cgi?id=77992) where
// timeStamp is not from The Epoch, it's from system start. So we work relative to the
// moment you clicked the first button rather than working with nice clean absolute data.

// Sadly, IE11 doesn't like you clicking the second button and then moving over to
// click the third, but the data from just clicking the second suggests it's more like
// Chrome than Firefox.
var start1;
var start2;
document.getElementById("start").addEventListener("click", function(e) {
  // Remember this event's timestamp
  start1 = e.timeStamp;
  start2 = 0;

  // Start a busy-loop for three seconds, locking up the main JS thread
  busy(3000);
  display("Done with first busy loop");
}, false);

document.getElementById("then1").addEventListener("click", function(e) {
  // Show time since first event
  showElapsed(e.timeStamp);

  // Remember this event's timetsamp
  start2 = e.timeStamp;

  // Another busy-loop, just a second this time
  busy(1000);
  display("Done with second busy loop");
}, false);

document.getElementById("then2").addEventListener("click", function(e) {
  // Show time since first and second events
  showElapsed(e.timeStamp);
}, false);

function showElapsed(ts) {
  display("Elapsed from first event: " + (ts - start1) + "ms");
  if (start2) {
    display("Elapsed from second event: " + (ts - start2) + "ms");
  }
}

function busy(duration) {
  var target = Date.now() + duration;
  while (Date.now () < target) {
    // Wait
  }
}

function display(msg) {
  var p = document.createElement('p');
  p.innerHTML = msg;
  document.body.appendChild(p);
}
function format(ts) {
  return new Date(ts).toISOString().substring(11, 23);
}
<input type="button" id="start" value="Click me">
<input type="button" id="then1" value="Then me quickly afterward">
<input type="button" id="then2" value="Then me quickly after that (not on IE!)">