Modern browsers almost all have a threaded scrolling feature that runs smoothly even when running computationally expensive JavaScript. However, this optimization may fail due to the need to wait for the results of event handlers such as TouchStart, TouchMove, or TouchEnd. The possible reason is to call preventDefault() in the Touch event handler to prevent scrolling completely.

Singsong: Wait for the result of the Touch event handler (whether to call preventDefault()) to expire. If it is called, block it completely; If no call is made, a scrolling delay starts.

addEventListener(
  document.'touchstart'.function (e) {
    e.preventDefault(); // Stop scrolling completely
  },
  false
);
Copy the code

The browser’s ability to prevent scrolling is actually rare, according to statistics:

Most touch event handlers never actually call preventDefault(), so browsers usually prevent scrolling unnecessarily. For example, in Chrome for Android, 80% of touch events that prevent scrolling never actually prevent scrolling (without calling preventDefault()). 10% of these events add more than 100ms of delay to the start of scrolling, and 1% of these add at least 500ms of delay.

To solve the above problems, the following optimization schemes are provided online:

  • Register an empty touch event handler in Document

    const touchHandler = function () {};
    document.addEventListener('touchmove', touchHandler);
    document.addEventListener('touchcancel', touchHandler);
    document.addEventListener('touchend', touchHandler);
    Copy the code
  • Use the CSS style touch-Action

    .classname {
      touch-action: none;
    }
    Copy the code

However, this problem does not only apply to touch events, but also to wheel events. To address this problem, the WHATWG has introduced Passive Event Listeners.

Passive Event Listeners are new to the DOM Spec. Chrome 51, Firefox 49, and Landed in WebKit have also started implementing Passive Event Listeners. It allows developers to optimize scrolling performance by identifying whether Touch or Wheel events need to prevent scrolling.

By marking a touch or wheel listener as passive, the developer is promising the handler won’t call preventDefault to disable scrolling.

addEventListener(
  document.'touchstart'.function (e) {
    e.preventDefault(); / / is invalid
  },
  { passive: true } // Explicitly tell the browser that preventDefault() will not be called to prevent scrolling
);
Copy the code

In this example, e.preventDefault() is called; The following information may be displayed on the console panel:

Unable to preventDefault inside passive event listener due to target being treated as passive.

If the touch or wheel handler is called preventDefault() with {passive: true} not enabled. The following information may be displayed on the console panel:

Violation] Added non-passive event listener to a asked-blocking ‘mousewheel’ event. Consider marking event handler as Money was strongly raised to make the page responsive.

Compare and optimize the effect of video

How to detectpassive

// Test via a getter in the options object to see if the passive property is accessed
var supportsPassive = false;
try {
  var opts = Object.defineProperty({}, 'passive', {
    get: function () {
      supportsPassive = true; }});window.addEventListener('testPassive'.null, opts);
  window.removeEventListener('testPassive'.null, opts);
} catch (e) {}

// Use our detect's results. passive applied if supported, capture will be false either way.
elem.addEventListener('touchstart', fn, supportsPassive ? { passive: true } : false);
Copy the code

Refer to the article

  • Passive event listeners
  • Passive event listeners explainer