Re: [whatwg/dom] High resolution timing for events (#23)

@birtles I have a reduced test case that I think illustrates the kinds of patterns that wouldn't be web-compatible, despite the apparent weirdness in Firefox:

```html
<html>
<body>
  <div id="output"></div>
  <input id="textbox" type="text" placeholder="focus here">
  <script>
    document.getElementById("textbox").onfocus = function(e) {
      var date = new Date();
      date.setTime(e.timeStamp || new Date());
      document.getElementById("output").innerHTML = "<p>" + date + "</p>";
    };
  </script>
</body>
</html>
```

This code worked in all browsers until the latest Chrome change. It relies on the fact that, for many events, the `timeStamp` is (interoperably) either the same as `new Date()` (as required by [DOM3](https://www.w3.org/TR/2011/WD-DOM-Level-3-Events-20110531) and [DOM4](https://dom.spec.whatwg.org/#dom-event-timestamp)) or `0` (as allowed by [DOM2](https://www.w3.org/TR/DOM-Level-2-Events/events.html)).

This reproduction is terse and works on all browsers other than the latest Chrome for all events that reliably provide `e.timeStamp` as either the DOM4 specified value **or** 0 (and there are many such events).

Some things to note:

### Firefox's "Zero"

While Firefox has, for a long time, returned `0` for many events, web developers learned to say `|| new Date()` to coerce the zero into a "good enough" date value.

This pattern is quite common (scan through [this GitHub search](https://github.com/search?p=2&q=%22e.timestamp+%7C%7C+new+Date%22&ref=searchresults&type=Code&utf8=%E2%9C%93) including in highly popular libraries.

The Angular bug was exactly this situation. Here's [the fix](https://github.com/angular/angular.js/pull/13495/files):

```diff
- var timeStamp = ev.$manualTimeStamp || ev.timeStamp || Date.now();
+ var timeStamp = ev.$manualTimeStamp || Date.now();
```

### `setTime`

It's easy to observe that developers expect the result of `e.timeStamp` to return a value that looks like a JavaScript date, because `date.setTime(e.timeStamp)` is [very common](https://github.com/search?l=javascript&q=setTime%28e.timeStamp+%7C%7C+new+Date%28%29%29&type=Code&utf8=%E2%9C%93).

As people have pointed out, that didn't always work on Firefox, but the `|| new Date()` workaround is shockingly common once people discover the problem. In fact, it's been a part of jQuery forever as part of its "event fix-up logic":

```js
this.timeStamp = src && src.timeStamp || jQuery.now();
```

Here it is [in the latest version of jQuery](https://github.com/jquery/jquery/blob/2.2-stable/src/event.js#L583) and here it is [in 2011](https://github.com/jquery/jquery/blob/8c91da57b9fbc8ded9854a899e4105530cea1d90/src/event.js).

In short, the existence of the `|| now()` and its adoption by jQuery means that the events that return `0` in Firefox still have a terse, common, and interoperable semantics that web developers depend on.

### Comparing to Fixed Times

Finally, Chrome seems to believe that the only valid comparison of an `e.timeStamp` is another `e.timeStamp`. In fact, there are two other valid comparisons:

* comparing `e.timeStamp` to a fixed time in the past (animation start, app load, etc.)
* comparing a previous `e.timeStamp` to the current time, when not directly inside an event handler.

These problems figured into virtually all of the already-known reproductions, and it's simply reasonable for developers to want to compare against a fixed time. Since `performance.now()` is relatively new, any developer in the past who wanted to compare a timestamp to a fixed timestamp had no choice but to compare to `Date.now()`, and that code is both reasonable and often not very easy to fix.

I would encourage people who believe that shipping in Chrome proves that the problem doesn't exist to search Stack Overflow and other avenues for people confused about the breakage in Chrome. It will only increase over time, and people asking questions only represent a small percentage of total web content with the breakage.

## The Standards Status Quo

DOM2 also allowed for a flexible epoch, but in practice a large percentage of all events were supplied (again, interoperably) as either milliseconds since `0:0:0 UTC 1st January 1970` or `0`. Before the recent change in Chrome, Firefox developers had [noticed](https://bugzilla.mozilla.org/show_bug.cgi?id=238041#c23) that DOM4 now required a unix-epoch-based timestamp, and jQuery [filed a bug](https://bugzilla.mozilla.org/show_bug.cgi?id=702015) against Firefox asking to fix the remaining events, which was closed as a duplicate of the bug tracking DOM4 behavior.

The TLDR is that until Chrome decided to make this change, the DOM spec had been increasing in precision, and browsers were coming into compliance.

### DOM2

> Used to specify the time (in milliseconds relative to the epoch) at which the event was created. Due to the fact that some systems may not provide this information the value of timeStamp may be not available for all events. When not available, a value of 0 will be returned. Examples of epoch time are the time of the system start or 0:0:0 UTC 1st January 1970.

### DOM3

> Used to specify the time at which the event was created in milliseconds relative to 1970-01-01T00:00:00Z.

### DOM4

> 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.

---
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/whatwg/dom/issues/23#issuecomment-214934566

Received on Wednesday, 27 April 2016 01:02:29 UTC