挪动Web转动机能优化: Passive event listeners

本年的 Google I/O 已过去一段时间了,大部分人都关注了一些新产品的宣布,比方 Allo 和 Duo、Android N、Daydream、Android Studio、Firebase……另有 PWA。

网上关于 PWA 相干的文章和手艺议论已许多了,然则关注 Passive event listeners 的文章却很少。那末 Passive event listeners 究竟有多奇异呢?

假如用简朴一句话来诠释就是:提拔页面滑动的流通度。

addEventListener 用来在页面中监听事宜,它的参数署名是如许的:

target.addEventListener(type, listener[, useCapture]);

然则假如你如今去查询 MDN 的文档却发明是如许写的:

target.addEventListener(type, listener[, options]);
target.addEventListener(type, listener[, useCapture]);

末了一个参数 useCapture 在良久之前是必填的,厥后的范例将 useCapture 变成了选填。useCapture 参数用来掌握监听器是在捕捉阶段实行照样在冒泡阶段实行,true 为捕捉阶段,false 为冒泡阶段,变成选填后默许值为 false(冒泡阶段),因为传 true 的状况太少了。

《挪动Web转动机能优化: Passive event listeners》

此历程被称为事宜流传。假如我们为每一个元素都绑定事宜,那末在事宜冒泡历程当中,子元素最早相应事宜,然后顺次向父元素冒泡。

在事宜处置惩罚函数中,会通报 Event 对象作为参数,而这个参数最常常运用的 2 个要领就是 event.preventDefault()event.stopPropagation()

  • stopPropagation() 阻挠事宜流传

  • preventDefault() 阻挠事宜的默许行动

在挪动网页中,我们常常运用的就是 touch 系列的事宜,如:

  • touchstart

  • touchmove

  • touchend

  • touchcancel

我们可以运用以下体式格局绑定 touchstart 事宜:

div.addEventListener("touchstart", function(e){
    // do sth.
})

因为第三个参数没有传值,那末默许就是 false,也就是这个事宜在冒泡阶段被处置惩罚,假如挪用了 stopPropagation()div 的父元素就没法吸收这个事宜。

那末假如我们挪用了 preventDefault() 呢?假如你曾给超链接 a 标签绑定过 click 事宜应当就晓得会发作什么了。当 a 标签点击时,它的默许行动是跳转到 href 指定的链接,假如我们挪用了 preventDefault 就阻挠了 a 标签点击事宜的默许行动。(假如你运用 jQuery 经由过程 return false 可以阻挠事宜默许行动,然则深记 You Might Not Need jQuery )

假如我们在 touchstart 事宜挪用 preventDefault 会怎样呢?这时刻页面会制止,不会转动或缩放。那末题目来了:浏览器没法预先晓得一个监听器会不会挪用 preventDefault(),它需要等监听器实行完后,再去实行默许行动,而监听器实行是要耗时的,如许就会致使页面卡顿。

这段翻译的太专业了,你可以这么明白:当你触摸滑动页面时,页面应当追随手指一同转动。而此时你绑定了一个 touchstart 事宜,你的事宜也许实行 200 毫秒。这时刻浏览器就犯含糊了:假如你在事宜绑定函数中挪用了 preventDefault,那末页面就不应当转动,假如你没有挪用 preventDefault,页面就需要转动。然则你究竟挪用了照样没有挪用,浏览器不晓得。只能先实行你的函数,等 200 毫秒后,绑定事宜实行完了,浏览器才晓得,“哦,原本你没有阻挠默许行动,好的,我立时滚”。此时,页面最先滚。

而且 Chrome 做了统计:

For instance, in Chrome for Android 80% of the touch events that block
scrolling never actually prevent it. 10% of these events add more than
100ms of delay to the start of scrolling, and a catastrophic delay of
at least 500ms occurs in 1% of scrolls.

在 Android 版 Chrome 浏览器的 touch 事宜监听器的页面中,80% 的页面都不会挪用 preventDefault 函数来阻挠事宜的默许行动。在滑动流通度上,有 10% 的页面增添最少 100ms 的耽误,1% 的页面以至增添 500ms 以上的耽误。

也就是说,当浏览器守候实行事宜的默许行动时,大部分状况是白等了。假如 Web 开辟者可以提早通知浏览器:“我不挪用 preventDefault 函数来阻挠事宜事宜行动”,那末浏览器就可以疾速天生事宜,从而提拔页面机能。

Chrome官方有个视频测试:https://www.youtube.com/watch… (需科学上网)

passive 就是为此而生的。在 WICG 的 demo 中提到,纵然转动事宜内里写一个死循环,浏览器也可以一般处置惩罚页面的滑动。

在最新的 DOM 范例中,事宜绑定函数的第三个参数变成了对象:

target.addEventListener(type, listener[, options]);

我们可以经由过程通报 passivetrue 来明白通知浏览器,事宜处置惩罚顺序不会挪用 preventDefault 来阻挠默许滑动行动。

在 Chrome 浏览器中,假如发明耗时凌驾 100 毫秒的非 passive 的监听器,会在 DevTools 内里正告你加上 {passive: true}

Chrome 51 和 Firefox 49 已支撑 passive 属性。假如浏览器不支撑,已有人做了异常奇妙地 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("test", 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
); 

这段代码值得细读,用的太奇妙了,几乎炫酷到没朋侪。

不过,遗憾的是各大主流框架都还未供应对 passive 的原生支撑:

React 框架番号为 #6436 的 issue 从本年 4 月 8 号就最先议论,官方家加的 label 是 “big picture”。

Support Passive Event Listeners · Issue #6436 · facebook/react

原本我以为 Angular 应当会供应对 passive 的原生支撑,然则我去搜了 issue。编号为 #8866 的 issue 残暴的通知我 Angular 也正在议论此事,而且时间比 React 还晚,5月27号。而 label 是 “state: Needs Design”。

[feat] Take advantage of passive event listeners · Issue #8866 · angular/angular

最不应当报什么愿望的就是 jQuery 了,毕竟关于一个连事宜捕捉都不支撑的框架来讲,很难设想它会支撑 passive。

去看了它的 issue,果然是前端最盛行的框架,在本年1月17号就有开辟者提了相干 issue 了。和 React Angular 差别,这个 issue 并非 jQuery 开辟成员提的。label 是 “Event”、 “Feature”、 “Web Standards”。

从 label 可以看出来对这个特征的注重,然则再看看 milestone 就难免有些心寒——4.0.0。

假如没以为心寒,可以继承点击进去看看 4.0.0 的开辟进度和宣布设计:

什么时刻宣布呢?No due date

开辟进度怎样呢?0% complete

我之前开辟过一个 Chrome 插件 ChromeSnifferPlus,可以检测当前页面运用了哪些框架,以及框架的版本号等信息。年终的时刻我曾剖析了一次统计状况,jQuery 版本运用最多的网站是 1.4. 和 1.7.

末了,也不要消极,上面只是说了这些框架并没有供应对 passive 的原生支撑,并不代表我们就不可以运用了。比方 React 的许多 scroll 组件,都运用了 passive 来提拔转动机能。

    原文作者:justjavac
    原文地址: https://segmentfault.com/a/1190000007913386
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞