Skip to content
This repository has been archived by the owner on Apr 16, 2019. It is now read-only.

Make all event listeners passive where supported #4

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/tracker/engaged_time.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,19 @@ limitations under the License.
root.focused = false;
});

var supportsPassive = false;
try {
addEventListener("test", null, Object.defineProperty({}, 'passive', {get: function () {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RByers I'm having a hard time grokking this logic. I understand it's meant to determine whether the browser supports passive listeners, but I don't exactly see how it's doing that. Can you clarify?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it's a little ugly / confusing, sorry about that. Basically the canonical way (only way at the moment) to feature detect for dictionary members is to pass a custom object to an API that takes the dictionary and see if the getter is invoked for the property of interest. WebIDL Ecmascript bindings require that the getter for each supported property is invoked when the function is called.

So in this case we do a dummy call to addEventListener (passing null as the handler is defined to be a no-op). We pass into that a custom object whose passive getter function just records that it has been called. There are four possible behaviors:

  1. Browser doesn't support addEventListener or defineProperty at all - throws, supportsPassive remains false.
  2. addEventListener expects only a boolean in the 3rd position. The object gets coerced to the value true without invoking the getter. supportsPassive remains false.
  3. addEventListener supports taking a dictionary in the 3rd position, but not the passive member. In that case other getters may be invoked, but not the one we've defined for passive. supportsPassive remains false.
  4. addEventListener supports the passive option. In that case the getter function we've defined gets run as part of the JavaScript API binding and supportsPassive will be true.

For context see the original design discussion and this WebIDL issue where we're considering exposing something less ugly.

supportsPassive = true;
}}));
} catch(e) {}
var optionsOrCapture = false;
if (supportsPassive)
optionsOrCapture = {passive:true, capture:false}

var _buildListener = function(event_name, callback) {
if (window.addEventListener) {
window.addEventListener(event_name, callback, false);
window.addEventListener(event_name, callback, optionsOrCapture);
} else {
document.attachEvent("on" + event_name, callback);
}
Expand Down