专栏首页京程一灯现代浏览器探秘(part4):事件处理 [每日前端夜话(0x14)]

现代浏览器探秘(part4):事件处理 [每日前端夜话(0x14)]

每日前端夜话0x14

每日前端夜话,陪你聊前端。

每天晚上18:00准时推送。

正文共:3718 字 10 图

预计阅读时间: 10 分钟

翻译:疯狂的技术宅 原文:https://developers.google.com/web/updates/2018/09/inside-browser-part4

前文回顾:

现代浏览器探秘(part1):架构 现代浏览器探秘(part2):导航 现代浏览器探秘(part3):渲染

当输入到达合成器

这是关于Chrome浏览器内部工作原理系列的最后一篇;研究浏览器怎样通过处理代码来显示网站。在上一篇文章中,我们研究了渲染过程并了解了合成器。 在本文中,我们将分析当用户输入时,合成器是怎样实现平滑交互的。

从浏览器的角度看输入事件

当你听到“输入事件”时,可能只会想到在文本框打字或鼠标单击,但从浏览器的角度来看,输入意味着来自用户的所有动作。 鼠标滚轮滚动是输入事件,触摸或者鼠标移动也是输入事件。

当发生类似在屏幕上的触摸的用户动作时,浏览器是最先先接收到动作的进程之一,但是浏览器进程只知道该动作发生的位置。因为选项卡内部的内容由渲染器进程处理,所以浏览器进程会把事件类型(如touchstart)及其坐标发送到渲染器进程。 渲染器进程通过查找事件目标并运行附加的事件侦听器来适当地处理事件。

图1:通过浏览器进程路由到渲染器进程的输入事件

合成器接收输入事件

在上一篇文章中,我们研究了合成器是如何通过合成栅格化图层来平滑地处理滚动的。 如果没有输入事件侦听器附加到页面,那么合成器线程可以创建完全独立于主线程的新复合帧。 但是如果一些事件监听器被附加到页面上会怎样呢? 如果需要处理事件,合成器线程将如何操作呢?

2:将鼠标悬停在页面图层上

了解非快速可滚动区域

由于JavaScript是运行在主线程上的,所以当合成页面时,合成器线程会标记页面的一个区域,该区域将事件处理程序附加为“非快速可滚动区域”。通过获取此信息,合成器线程可以确保在该区域中发生事件时将输入事件发送到主线程。 如果输入事件来自该区域之外,则合成器线程在不等待主线程的情况下进行合成新帧。

图3:输入到非快速可滚动区域的示意图

在编写事件处理程序时要注意

Web开发中常见的事件处理模式是事件委托。 由于事件冒泡,你可以在最顶层的元素上附加一个事件处理程序,并根据事件目标委派任务。 你可能看到过或写过类似下面的代码。

由于你只需要为所有元素编写一个事件处理程序,因此该事件委托模式在工程上很有吸引力。 但是如果从浏览器的角度来看这段代码,整个页面都被标记成了非快速可滚动区域。那么这意味着什么呢?即使你的应用不关心页面中某些部分的输入,合成器线程也必须与主线程通信,并且在每次输入事件进入时都要等待它。因此合成器的平滑滚动能力被破坏了。

图4:在覆盖整个页面的非快速可滚动区域进行输入

为了缓解这种情况,你可以在事件侦听器中传递passive:true选项。 这向浏览器提示你仍然希望在主线程中监听事件,同时合成器也可以继续并合成新帧。

检查事件是否可取消

想象一下,在页面中有一个框,你希望仅将滚动方向限制为水平滚动。

在鼠标事件中使用 passive:true 选项意味着可以平滑滚动页面,但是在你想要用preventDefault 来限制滚动方向时,垂直滚动可能已经开始了。 你可以使用event.cancelable方法对这种情况进行检查。

图5:一个部分内容被固定为水平滚动的网页

或者你可以使用CSS规则(例如touch-action)来完全消除事件处理程序。

查找事件目标

当合成器线程向主线程发送输入事件时,首先要做的是命中测试以查找事件目标。 命中测试查找事件发生的坐标之下的内容,它使用在渲染进程中生成的绘制记录数据来完成这一使命。

图6:查看绘制记录的主线程询问在x.y坐标点上绘制的内容

最小化事件发送到主线程

在上一篇文章中,我们讨论了我们的显示器以每秒60次的频率刷新的机制,以及我们怎样跟上节奏来获得流畅的动画效果。 对于输入来说,典型的触摸屏设备每秒发送60-120次触摸事件,而典型的鼠标每秒发送100次事件。 输入事件具有比屏幕刷新更高的保真度。

如果类似touchmove的连续事件被发送到主线程120次,那么与屏幕刷新的速度相比,它可能会触发过多的命中测试和JavaScript的执行。

图7:充斥在帧时间线上的事件导致页面闪烁

为了最大限度地减少对主线程的过度调用,Chrome会合并连续事件(例如wheel, mousewheel, mousemove, pointermove, touchmove),并进行延迟调度,直到下一个 requestAnimationFrame

图8:与上图相同的时间线,但是正在合并和延迟事件

任何离散事件,例如 keydownkeyupmouseupmousedowntouchstart、和 touchend 都会被立即发送。

使用 getCoalescedEvents 获取帧内事件

对于大多数Web应用程序,合并事件应足以提供良好的用户体验。 但是如果要构建一个绘图应用并根据 touchmove 坐标放置路径,则可能会在绘制平滑线时丢失中间坐标。 在这种情况下,你可以在鼠标事件中使用getCoalescedEvents方法来获取有关这些合并事件的信息。

图9:左侧是平滑的触摸手势路径,右侧是合并限制路径

下一步

在本系列中,我们介绍了Web浏览器的内部工作原理。 如果你从未想过为什么"开发者工具"建议在你的事件处理中添加{passive: true}或者为什么你可以在脚本标记中编写async属性,我希望本系列能够说明为什么浏览器需要这些信息来提供更快更顺畅的体验。

使用Lighthouse

如果你想让自己的代码对浏览器友好,但不知道从哪里开始,可以使用Lighthouse(https://developers.google.com/web/tools/lighthouse/)这个网站审计工具,它为你提供一份报告,说明正在做什么和需要改进什么。 阅读审核列表还可以让你了解浏览器关注的内容。

了解如何衡量性能

不同网站的性能调整可能会有所不同,因此,衡量网站的效果并确定最适合你网站的内容至关重要。 Chrome DevTools团队没多少关于如何衡量网站性能的教程。

向你的站点添加功能策略

功能策略是一个新的Web平台功能,可以在你构建项目时为你提供保护。 启用功能策略可确保应用的某些行为并防止你出错。 例如,如果要确保应用永远不会阻止解析,或者可以在同步脚本策略上运行应用。 启用 sync-script: 'none' 时,将禁止解析器阻止 JavaScript 执行。 这可以防止你的代码阻止解析器,并且浏览器也不需要担心暂停解析器。

总结

thank you(图中有作者的推特)

当开始构建网站时,我几乎只关心如何编写代码以及怎样才能帮助我提高工作效率。 这些很重要,但我们也应该考虑浏览器如何获取我们编写的代码。 现代浏览器将继续致力于为用户提供更好的Web体验。 反过来通过使代码对浏览器友好,也可以改善你的用户体验。 希望我们一起努力追求更好的浏览器!

本文分享自微信公众号 - 京程一灯(jingchengyideng),作者:京程一灯

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-01-16

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • three.js 新手指南

    在这个分步指南中,我们将使用一个基于 WebGL 的 3D 图形的框架 three.js, 创建一个 3D 版本的 Treehouse 徽标。你可以通过点击或者...

    疯狂的技术宅
  • Node.js 框架 express 4.X API 中文手册【express()篇】

    写过 node.js 应用的小伙伴们应该都知道 express 应用框架,它让我们在开发时候的路由设计简化,直接方便我们快速的开发,然而,因为版本更新的太快,导...

    疯狂的技术宅
  • 【译】理解Service Worker

    PWA是最近前端最火热的一个概念之一,Service Worker为PWA赋能离线可用性以及push消息。

    疯狂的技术宅
  • C#系列学习笔记之事件

    需要使用winform来实现传入图片的base64值,调用接口,返回结果这样的一个功能。大致的设置如下图:

    算法发
  • JavaScript中的Event(事件)详解

    时间静止不是简史
  • javascript事件流的原理

    事件是用户或浏览器自身执行的某种动作,如click,load和mouseover都是事件的名字。

    前端老鸟
  • js高程之事件通识篇(一)

    在早期的浏览器厂商都认为页面中的元素事件都不仅仅是当前元素上,而是相关的其他元素甚至整个页面都应该相关的机制。但有意思的是,早期的两个开发团队分别是ie和Net...

    RobinsonZhang
  • 微服务架构下的数据一致性保证(二)

    大家好,今天是第二次在这里给大家分享数据一致性的话题,在第一篇分享中我们介绍了微服务架构下应该满足数据最终一致性原则,并介绍实现最终一致性3种模式。 本文是...

    yuanyi928
  • 事件机制

    DOM事件模型分为捕获和冒泡。一个事件发生后,会在子元素和父元素之间传播(propagation)。事件传播分为三个阶段:

    Cloud-Cloudys
  • JQuery之内置函数响应事件

    今天给大家介绍一下on函数中events的种类和用法。 具体我把它分为:键盘事件,鼠标事件,input事件,还有一个是基础事件(例如:滚动,界面大小变化等等之类...

    林老师带你学编程

扫码关注云+社区

领取腾讯云代金券