合成器有输入源
本文是“Chrome 浏览器”系列博文(共 4 部分)中的最后一部分;调查它如何处理 我们的代码来显示网站在上一篇博文中,我们介绍了渲染过程并了解了合成器。在本文中,我们将 我们看看在用户输入内容时,合成器如何实现流畅的交互。
从浏览器的角度输入事件
当你听到“输入事件”时您可能只会想到在文本框中进行输入或点击鼠标, 从浏览器的角度来看,输入表示用户执行的任何手势。鼠标滚轮滚动是一项输入 事件,触摸或鼠标悬停也是一个输入事件。
当在屏幕上发生触摸等用户手势时,浏览器进程就是接收
手势。但是,浏览器进程只能知道该手势的发生位置,
标签页内的内容由渲染程序进程处理。因此,浏览器进程将事件
类型(如 touchstart
)及其坐标传递给渲染程序进程。渲染程序进程负责处理
通过查找事件目标并运行附加的事件监听器来相应地触发该事件。
合成器接收输入事件
在上一篇博文中,我们了解了合成器如何通过 光栅化图层。如果页面未附加任何输入事件监听器,则合成器线程 创建完全独立于主线程的新复合框架。但如果某些活动 监听器附加到了网页?合成器线程如何确定事件是否需要 处理方式?
了解不可快速滚动的区域
由于运行 JavaScript 是主线程的工作,因此在合成页面时,合成器线程 将附加了事件处理脚本的网页区域标记为“非快速滚动区域”。修改者 获得这些信息后,合成器线程可以确保将输入事件发送到主线程 如果事件发生在该地区如果输入事件来自该区域之外,那么 合成器线程会开始合成新帧,而不等待主线程。
编写事件处理脚本时要注意
Web 开发中的一种常见的事件处理模式是事件委托。由于事件气泡 可以在最顶端的元素上附加一个事件处理脚本,并根据事件目标委托任务。您 可能曾查看或编写过如下代码。
document.body.addEventListener('touchstart', event => {
if (event.target === area) {
event.preventDefault();
}
});
由于您只需为所有元素编写一个事件处理脚本,因此该事件的工效学设计是 很有吸引力但是,如果您从浏览器的角度来看 视图,现在整个页面都会被标记为不可快速滚动的区域。这意味着,即使您的 应用并不在意来自页面某些部分的输入,因此合成器线程必须 与主线程进行通信,并在每次有输入事件进入时等待主线程。因此, 合成器的流畅滚动功能失效。
为了减少这种情况的发生,您可以在事件中传递 passive: true
选项
监听器。这将提示浏览器您仍想监听主线程中的事件,
但合成器也可以继续合成新帧
document.body.addEventListener('touchstart', event => {
if (event.target === area) {
event.preventDefault()
}
}, {passive: true});
检查活动是否可取消
假设您在网页上有一个框,您希望将滚动方向限制为仅水平滚动。
在指针事件中使用 passive: true
选项意味着页面可以顺畅滚动,但
自动滚动可能在您所需的时间preventDefault
开始,以限制
滚动方向。您可以使用 event.cancelable
方法对此进行检查。
document.body.addEventListener('pointermove', event => {
if (event.cancelable) {
event.preventDefault(); // block the native scroll
/*
* do what you want the application to do here
*/
}
}, {passive: true});
或者,您也可以使用 CSS 规则(如 touch-action
)来完全消除事件处理脚本。
#area {
touch-action: pan-x;
}
查找事件目标
当合成器线程向主线程发送输入事件时,首先要运行的是 以便找到事件目标点击测试使用绘制记录在渲染中生成的数据 过程找出事件发生的点坐标下面的内容。
尽可能减少向主线程分派事件的次数
在上一篇博文中,我们讨论了典型的显示屏如何每秒刷新 60 次 我们需要如何跟上流畅动画的节奏。对于输入,典型的触摸屏 设备每秒传递触摸事件 60-120 次,一般鼠标每秒传递事件 100 次 。输入事件的保真度高于屏幕可以刷新的保真度。
如果 touchmove
等连续事件每秒向主线程发送 120 次,则
与网页访问速度相比,
屏幕可以刷新。
为尽可能减少对主线程的过多调用,Chrome 会合并连续事件(例如
wheel
、mousewheel
、mousemove
、pointermove
、touchmove
),并延迟调度至
就在下一个requestAnimationFrame
之前。
任何离散事件,例如 keydown
、keyup
、mouseup
、mousedown
、touchstart
和 touchend
所有资源
使用 getCoalescedEvents
获取帧内事件
对于大多数 Web 应用,合并事件应该足以提供良好的用户体验。
不过,如果您要构建一些内容,例如绘制应用,
touchmove
坐标,则可能会丢失中间的坐标,以绘制平滑线。在这种情况下
则可以在指针事件中使用 getCoalescedEvents
方法获取有关这些事件的信息
合并事件
window.addEventListener('pointermove', event => {
const events = event.getCoalescedEvents();
for (let event of events) {
const x = event.pageX;
const y = event.pageY;
// draw a line using x and y coordinates.
}
});
后续步骤
在本系列中,我们介绍了网络浏览器的内部工作原理。如果你从未想过
开发者工具建议在事件处理脚本上添加 {passive: true}
或编写 async
的原因
属性,我希望本系列视频能帮助您
了解浏览器为何需要使用这些属性
从而提供更快速、更顺畅的网络体验。
使用 Lighthouse
如果您希望代码对浏览器有益,但又不知道从何处入手, Lighthouse 是一款可对任何网站进行审核的工具,可为您提供 报告哪些方面做得不错,哪些方面需要改进。仔细阅读审核列表 也可以让您了解浏览器关注哪些内容。
了解如何衡量性能
性能调整可能因网站而异,因此衡量广告效果至关重要 并确定哪些内容最适合您的网站。Chrome 开发者工具团队关于 如何衡量网站性能。
向您的网站添加功能政策
如果想要更进一步,功能政策是一项新功能
Web 平台功能,可作为您构建项目时的保障。正在开启
功能政策可保证应用的某些行为,并防止您出错。
例如,如果您想确保应用永远不会阻止解析,则可以在
同步脚本政策。sync-script: 'none'
已启用后,会阻止解析器的 JavaScript
无法执行。这可以防止您的任何代码阻止解析器,而
因此浏览器无需担心暂停解析器。
小结
刚开始构建网站时,我几乎只关心如何编写代码,以及 有助于我提高工作效率这些都很重要,但我们还应该考虑 浏览器接受我们编写的代码。现代浏览器一直并且仍在继续投资 为用户提供更好的网络体验。我们通过整理代码来为浏览器美化 从而改善用户体验希望您和我一起为浏览器友善!
非常感谢审核本系列早期草稿的所有人,包括(但不限于) Alex Russell、 Paul Ireland, Meggin Kearney, Eric Bidelman, Mathias Bynens, Addy Osmani: Kinuko Yasuda, Nasko Oskov、 以及 Charlie Reis。
您喜欢这个系列吗?如果您对以后的帖子有任何疑问或建议, 期待在下面的评论部分或 @kosamari 提供宝贵意见 。