[译]深入了解现代web浏览器(四)
本文是根据Mariko Kosaka在谷歌开发者网站上的系列文章https://developer.chrome.com/blog/inside-browser-part4/翻译而来,共有四篇,该篇是第四篇。对于其中一些直译出来不太好理解的句子,笔者做了加工处理和提炼。
输入来到了合成器
在上篇文章中,我们了解了渲染过程和合成器;在这片文章中,我们将来了解下合成器是如何在用户输入到来时保持交互流畅的。
从浏览器的角度看输入事件
当你听到“输入事件”时,你可能只会想到在文本框中输入或是鼠标点击;但从浏览器的角度来看,来自用户的任何动作都是输入。鼠标滚轮滚动、触摸或者鼠标悬浮都是一个输入事件。
当用户在屏幕做出触摸等动作时,浏览器进程最先接收到该动作。但是浏览器进程只关注该动作发生的位置,因为tab页中的内容是由渲染进程处理的。浏览器进程把事件类型(比如touchstart)和其坐标发送给渲染进程;渲染进程会找到对应的事件目标并执行目标上绑定的事件监听器。

通过浏览器进程路由到渲染进程的输入事件
合成器接收输入事件
在上一篇文章中,我们知道了合成器是如何通过合成光栅化的图层来达到流畅地处理滚动的。如果页面上没有绑定事件监听,合成线程可以完全独立于主线程来创建合成帧。但如果页面上绑定有事件监听呢?毕竟事件监听的回调函数只能由主线程来执行。
理解非快速滚动区域
由于运行Javascript是主线程的工作,当页面被合成时,合成线程会将页面上绑定有事件监听的区域标记为“非快速滚动区域(Non-Fast Scrollable Region)”。拥有这些信息,合成线程能够确保当有事件发生在该区域时能将输入事件发送给主线程。如果输入事件是来自该区域之外的,则合成线程会继续合成新的帧而无需等待主线程执行事件处理函数。

非快速滚动区域的输入事件
注意你编写的事件处理函数
在web开发中一种很常见的处理模式是事件委派。由于事件冒泡机制的存在,你可以在最顶层的元素绑定事件处理函数然后根据事件目标来委派处理函数。你可能见过或者写过如下的代码:
document.body.addEventListener('touchstart', event => {
if (event.target === area) {
event.preventDefault();
}
});
由于你只需要为所有的元素只编写一个处理函数,从工程学上讲这种事件委派模式很有吸引力。但如果从浏览器的角度来看这段代码,现在整个页面都被标记为了“非快速滚动区域”。这意味着,即使你的应用并不关心页面上某些部分产生的输入事件,但只要发生了输入事件,合成线程还是不得不与主线程发生通信并等待。因此,合成线程的流畅性就会收到影响。

覆盖到了整个页面的非快速滚动区域
为了减轻这种情况的影响,你可以向事件处理函数中传入passive: true选项。这能提示浏览器你在事件处理函数中不会调用event.preventDefault(),就意味着你代码中不会通过event.preventDefault()语句阻止事件的默认行为(没有这个选项的话,则需要主线程执行完你的处理函数然后才能决定是否要阻止诸如滚动、失焦之类的事件默认行为,再告知合成线程要合成新的帧)。因此,在有passive: true的情况下,就可以让主线程在执行处理函数的同时,合成线程能继续合成下一帧。
document.body.addEventListener('touchstart', event => {
if (event.target === area) {
event.preventDefault()
}
}, {passive: true});
寻找事件目标
当主线程收到合成线程发送的输入事件后,首先要做的就是执行命中测试来找到事件目标。命中测试利用渲染阶段生成的绘制记录来找出发生事件的点坐标下方的内容。

主线程根据绘制记录查询x.y点处绘制的内容
最小化事件调度到主线程
在上一篇文章中,我们讨论了典型的显示器是如何一秒钟刷新60次并保持动画流畅的节奏。对于输入,典型的触屏设备每秒会传递60-120次触屏事件,而典型的鼠标每秒会传递100次事件。输入事件的保真度高于我们屏幕刷新频率的保真度。
如果像touchmove这样的连续事件被每秒120次地发送到主线程,那么与屏幕的刷新速度相比,它会触发过多的命中测试和Javascript执行。

帧的时间轴上被大量事件淹没导致页面卡顿
为了尽量减少在主线程上的调用,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.
}
})
下一步
在本系列中,我们介绍了Web浏览器的内部工作原理。如果您从未想过为什么DevTools建议在事件处理程序中添加{passive: true},或者为什么你可能要在脚本标签中写入async属性;我希望本系列文章能够阐明为什么浏览器需要这些信息来提供更快、更流畅的Web体验。
使用Lighthouse
如果你想让自己的代码对浏览器更友好但不知道从哪里开始,Lighthouse会是一个不错的工具。它可以对任何网站执行审计并提供一份报告,告知你哪些地方做的不错而哪些地方还需要改进。通过阅读审计列表,可以让你知道浏览器关心哪些指标。
了解如何衡量性能
对于不同站点性能调整会有所不同,因此如何衡量你的站点性能并确定最适合的方案是非常重要的。Chrome的DevTools团队有一些关于衡量站点性能的教程。
总结
当我开始构建网站的时候,几乎只关心书写代码和哪些能帮助我提高效率的东西。这些事当然很重要,但我们也应该思考下浏览器是如何处理我们书写的代码的。现代浏览器为给用户提供更好的web体验而持续努力。书写对浏览器“友好”的代码,这反过来会改进你的用户体验。希望你能加入我们一起追求对浏览器更为友好的世界!
[译]深入了解现代web浏览器(四)的更多相关文章
- [译]36 Days of Web Testing(四)
Day 19: UX 用户体验 Why ? 最近UX变得越来越火,用户提现往往会直接联想到易用性和设计. 在我看来,UX不仅仅是这两点.UX, User Experience ,对我而言,不单单是产 ...
- [C# 网络编程系列]专题四:自定义Web浏览器
转自:http://www.cnblogs.com/zhili/archive/2012/08/24/WebBrowser.html 前言: 前一个专题介绍了自定义的Web服务器,然而向Web服务器发 ...
- 转:【专题四】自定义Web浏览器
前言: 前一个专题介绍了自定义的Web服务器,然而向Web服务器发出请求的正是本专题要介绍的Web浏览器,本专题通过简单自定义一个Web浏览器来简单介绍浏览器的工作原理,以及帮助一些初学者揭开浏览器这 ...
- 专题四:自定义Web浏览器
前言: 前一个专题介绍了自定义的Web服务器,然而向Web服务器发出请求的正是本专题要介绍的Web浏览器,本专题通过简单自定义一个Web浏览器来简单介绍浏览器的工作原理,以及帮助一些初学者揭开浏览器这 ...
- 前端Web浏览器基于Flash如何实时播放监控视频画面(四)之使用videoJs‘拉流’
本片文章只是起到抛砖引玉的作用,能从头到尾走通就行,并不做深入研究.为了让文章通俗易懂,尽量使用白话描述. 0x001: 下载videoJs 对于Video.js 5.x及更低版本,Flash技术(v ...
- C#实现多级子目录Zip压缩解压实例 NET4.6下的UTC时间转换 [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了 asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程 asp.net core异步进行新增操作并且需要判断某些字段是否重复的三种解决方案 .NET Core开发日志
C#实现多级子目录Zip压缩解压实例 参考 https://blog.csdn.net/lki_suidongdong/article/details/20942977 重点: 实现多级子目录的压缩, ...
- java web 学习四(http协议)
一.什么是HTTP协议 HTTP是hypertext transfer protocol(超文本传输协议)的简写,它是TCP/IP协议的一个应用层协议,用于定义WEB浏览器与WEB服务器之间交换数据的 ...
- JavaScript权威指南--WEB浏览器中的javascript
知识要点 1.客户端javascript window对象是所有客户端javascript特性和API的主要接入点.它表示web浏览器的一个窗口或窗体,并且可以用window表示来引用它.window ...
- 前端Web浏览器基于Flash如何实时播放监控视频画面(前言)之流程介绍
[关键字:前端浏览器如何播放RTSP流画面.前端浏览器如何播放RTMP流画面] 本片文章只是起到抛砖引玉的作用,能从头到尾走通就行,并不做深入研究.为了让文章通俗易懂,尽量使用白话描述. 考虑到视频延 ...
- Kendo UI for jQuery使用教程:支持Web浏览器
[Kendo UI for jQuery最新试用版下载] Kendo UI目前最新提供Kendo UI for jQuery.Kendo UI for Angular.Kendo UI Support ...
随机推荐
- 企业诊断屋:在线小说企业如何用A/B测试赋能业务
更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 近两年来,在线小说领域业务发展"降速",相较于几年前的快速扩张,2022年后国内在线小说企 ...
- PPT 快速生成图片墙
图片墙有什么用? 掌握以后,做封面就不慌了.减轻了找素材的压力 手动排列 插入任意大小矩形,好处,不需要对插入的张图片单独调整大小 右击进行组合,然后拉面整个PPT页面 插入8张图片 设置蒙版 画个大 ...
- MP4 视频“只闻其声,不见其人”,是怎么回事呢?
艾瑞巴蒂大家好,我二狗子又来啦!这段时间关于疫情的好消息不断,各个地区的疫情都得到了有效的控制,做到了新增病例个位数增长甚至连续多天零增长!这不,二狗子也终于可以出村回到大城市上班啦!由于要坐很久的火 ...
- DNS--安装&&配置文件
1 下载 #下载服务yum -y install bind#下载解析工具yum -y install bind-utils 2 配置文件 主配置文件 /etc/named.conf 区配置文件 /va ...
- Windows10/11 wsl2 安装 ArchLinux 子系统
这篇文章针对的是在win11系统的wsl2下安装ArchLinux系统,网上很多中文教程都是使用LxRunOffline去做的,但是实际上该方法已经过时了,目前有更加先进的ArchWSL方式. 如果用 ...
- #1198:Farm Irrigation(DFS + 并查集)
Farm Irrigation **Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) T ...
- PTA 天梯赛 L3-003 社交集群(并查集)
当你在社交网络平台注册时,一般总是被要求填写你的个人兴趣爱好,以便找到具有相同兴趣爱好的潜在的朋友.一个"社交集群"是指部分兴趣爱好相同的人的集合.你需要找出所有的社交集群. 输入 ...
- 详解KubeEdge EdgeMesh v1.15 边缘CNI特性
本文分享自华为云社区<KubeEdge EdgeMesh v1.15 边缘CNI特性原理及功能详解>,作者:达益鑫 |南开大学,刘家伟.吴锟 |DaoCloud,王杰章 |华为云 特性研发 ...
- 即学即会 Serverless | 如何解决 Serverless 应用开发部署的难题?
本文节选自<Serverless 开发速查手册>,关注Serverless 公众回复 手册 即可获得下载链接 作者 | 江昱(阿里云 Serverless 产品经理) 破局:工具链体系匮乏 ...
- qsort函数使用方法总结(详细全面+代码)
目录 qsort函数原型 compar参数 int 数组排序 结构体排序 字符串指针数组排序 字符串二维数组排序 整型二维数组(力扣题目) qsort函数原型 void qsort( void *ba ...