Added non-passive event listener to ascroll- blocking ‘mousewheel‘event Consider marking event handl

紳士的可怖發表於2020-11-20

[Violation ] Added non-passive event listener to ascroll- blocking 'mousewheel’event Consider marking event handler as ’ passive’to make the page more responsive. See https: com/feature/574554 3795965952

翻譯:

[衝突]在ascroll中新增了非被動事件偵聽器-阻塞“mousewheel”事件考慮將事件處理程式標記為“passive”,以使頁面更具響應性。參見https:com/feature/574554 3795965952

解決辦法:

npm i default-passive-events -S
main.js import 'default-passive-events'

擴充分析:

被動事件監聽器

被動事件偵聽器是DOM規範中的一項新功能,使開發人員可以選擇消除滾動和阻塞事件監聽器而無需滾動來選擇更好的滾動效能。開發人員可以使用來註釋觸控和滾輪偵聽器,{passive: true}以表示它們將永遠不會呼叫preventDefault。此功能在Chrome 51,Firefox 49和WebKit中都有提供。觀看下面的視訊,瞭解正在執行的被動事件偵聽器的並排:

問題

流暢的滾動效能對於網路上的良好體驗至關重要,尤其是在基於觸控的裝置上。所有現代瀏覽器具有螺紋滾動功能,允許滾動時昂貴的JavaScript執行平穩甚至可以執行,但是這種優化的一部分由需要等待的任何結果大敗touchstart和touchmove處理程式,這可能會阻止滾動完全由呼叫preventDefault()上事件。儘管在某些特定情況下作者可能確實希望阻止滾動,但分析表明,網路上的大多數觸控事件處理程式從未真正呼叫過preventDefault(),因此瀏覽器經常會不必要地阻止滾動。例如,在Android版Chrome瀏覽器中,有80%的阻止滾動的觸控事件從未真正阻止過滾動。這些事件中的10%給滾動開始增加了超過100ms的延遲,在1%的滾動中發生了至少500ms的災難性延遲。

許多開發人員驚訝地發現,僅向其文件新增空的觸控處理程式會對滾動效能產生重大的負面影響。開發人員非常合理地期望觀察事件的行為不會有任何副作用。

這裡的基本問題不僅限於觸控事件。wheel事件 遭受相同的問題。相反,指標事件處理程式的設計宗旨是永不延遲滾動(儘管開發人員可以通過touch-actionCSS屬性宣告性地完全取消滾動),因此不要遭受此問題的困擾。本質上,被動事件偵聽器建議將指標事件的效能屬性引入觸控和滾輪事件。

該提議為作者提供了一種在處理程式註冊時指示處理程式是否可以呼叫preventDefault()該事件(即,是否需要可取消的事件)的方式。當特定點上沒有觸控或滾輪處理程式需要取消事件時,使用者代理可以自由地立即開始滾動,而無需等待JavaScript。也就是說,被動監聽器沒有令人驚訝的效能副作用。

EventListenerOptions

首先,我們需要一種將附加資訊附加到事件偵聽器的機制。今天,captureto的引數addEventListener是類似這樣的最接近的示例,但是它的用法非常不透明:

 document.addEventListener('touchstart', handler, true);

EventListenerOptions 讓我們將其更明確地寫為:

document.addEventListener('touchstart', handler, true);

這只是現有行為的新(可擴充套件)語法-指定是要在捕獲階段還是冒泡階段呼叫偵聽器。

解決方案:“被動”選項

現在,我們有了在事件處理程式註冊時用於指定選項的可擴充套件語法,我們可以新增一個新passive選項,該選項預先宣告偵聽器永遠不會preventDefault()在事件上呼叫。如果是這樣,則使用者代理將忽略該請求(理想情況下至少生成一個控制檯警告),就像它對的事件一樣Event.cancelable=false。開發人員可以通過Event.defaultPrevented在呼叫之前和之後進行查詢來驗證這一點preventDefault()。例如:

  addEventListener(document, "touchstart", function(e) {
    console.log(e.defaultPrevented);  // will be false
    e.preventDefault();   // does nothing since the listener is passive
    console.log(e.defaultPrevented);  // still false
  }, Modernizr.passiveeventlisteners ? {passive: true} : false);

現在,瀏覽器不再需要在有任何觸控或滾輪偵聽器時阻止滾動,而僅在存在非被動偵聽器時才需要這樣做(請參見TouchEvents spec)。 passive偵聽器沒有效能方面的副作用。

通過將觸控或滾輪偵聽器標記為passive,開發人員保證處理程式不會呼叫preventDefault以禁用滾動。 這樣可以釋放瀏覽器,使其立即響應滾動,而無需等待JavaScript,從而確保為使用者提供可靠的平滑滾動體驗。

特徵檢測

由於較早的瀏覽器會將第3個引數中的任何物件解釋為該引數的true值capture,因此對於開發人員而言,在使用此API時使用功能檢測或polyfill至關重要,以避免意外的結果。特定選項的功能檢測可以如下進行:

// 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); 

為了簡化此過程,您可以使用“檢測它”中的功能檢測,例如:

  elem.addEventListener('touchstart', fn,
    detectIt.passiveEvents ? {passive:true} : false);

Modernizr在這裡也有檢測。關於為字典成員特徵檢測提供更簡單的API,存在著開放標準的爭論。

無需取消事件

在某些情況下,作者可能有意通過取消所有觸控或滾輪事件來始終禁用滾動。這些包括:

平移和縮放地圖

全頁/全屏遊戲
在這些情況下,當前行為(可以防止滾動優化)非常合適,因為始終可以防止滾動本身。在這些情況下,無需使用被動偵聽器,儘管應用touch-action: noneCSS規則來明確您的意圖通常仍然是一個好主意(例如,使用Pointer Events而不是Touch Events支援瀏覽器)。
但是,在許多常見情況下,事件不需要阻止滾動-例如:
僅監視使用者上次活動時間的使用者活動監視
touchstart 隱藏一些活動UI的處理程式(如工具提示)
touchstart和為touchendUI元素設定樣式的處理程式(不抑制click事件)。
對於這些情況,passive可以新增該選項(具有適當的功能檢測),而無需任何其他程式碼更改,從而顯著提高了滾動體驗。

在一些更復雜的場景中,處理程式僅希望在某些條件下抑制滾動,例如:

水平滑動以旋轉轉盤,鬆開物件或露出抽屜,同時仍允許垂直滾動。
在這種情況下,請使用touch-action:pan-y宣告性地禁用沿水平軸開始的滾動,而無需呼叫preventDefault()(測試頁)。
為了繼續在所有瀏覽器中正常工作,對的呼叫preventDefault應以對touch-action所使用的特定規則缺乏支援為條件(請注意Safari 9當前僅支援touch-action: manipulation)。
一個UI元素(如YouTube的音量滑塊),可在水平輪事件上滑動而不會更改垂直輪事件上的滾動行為。由於輪事件沒有等效的“觸控動作”,因此這種情況只能用非被動的輪偵聽器來實現。
事件委託模式將新增偵聽器的程式碼不知道使用者是否取消事件。
這裡的一種選擇是分別為被動和非被動偵聽器進行委派(就像它們完全是不同的事件型別一樣)。
也可以touch-action像上面一樣利用(處理Point Events的Touch Events)。

除錯和衡量收益

您可以通過chrome:// flags /#passive-listener-default(Chrome 52中的新增功能)將觸控/滾輪監聽器強制為被動,從而快速瞭解可能帶來的好處(以及潛在的損壞)。

Chrome小組正在為PerformanceTimeline API和更多DevTools功能制定提案,以幫助網路開發人員今天更好地瞭解此問題。

減少和分解長期執行的JS仍然很關鍵

當頁面表現出明顯的滾動空白時,始終表示某個地方存在潛在的效能問題。被動事件偵聽器無法解決這些潛在問題,因此我們仍強烈建議開發人員確保其應用程式符合RAIL準則即使在低端裝置上。如果您的網站一次執行的邏輯時間大於100毫秒,則響應點選/點選仍然會反應遲鈍。被動事件偵聽器僅允許開發人員將在滾動效能中反映出JS響應性的問題與監視輸入事件的需求分離開。特別是,第三方分析庫的開發人員現在可以放心,他們使用輕量級事件偵聽器不會從根本上改變使用其程式碼的任何頁面的觀察到的效能特徵。

相關文章