Open iidear opened 5 years ago
万维网最初的提案 https://www.w3.org/History/1989/proposal.html
介绍了万维网出现的背景以及基本的设计思路。
CERN(欧洲核研究组织)管理着多个大型的项目和试验。这些项目涉及的数据量大且不断在增加,很容易导致数据丢失。如何管理这些数据和信息成了一个很大的问题。基于此,Tim Berners-Lee 提出了一种基于分布式超文本系统的信息管理方案。
在数据量不断增长的情况下,把每份数据拆成独立的节点,然后通过连接把相关数据节点组织起来,是一种更合适的方式。树形结构是组织数据的一种方式,问题在于树无法对数据间的关系很好地建模,因为节点之间的连接关系是交错的。使用关键字(类似HashMap)也是一种方式,问题在于使用的人需要对系统和各个关键字都很熟悉。当时存在的超文本系统是一种可取的方案。
然后提案分析了 CERN 的需求
后面是一些概念图和排期。
从背景说明、问题分析、方案评估与选择、系统需求分析、系统基本模型、到任务排期。思路清晰完整。因为当时应用场景的限定,忽略了一些问题,导致一些缺陷到今天还被诟病(比如安全)。不过总的来说还是很棒。
用作者另一篇文章的话来说,
actually the inventing it was easy. ... the difficult bit was persuading people to join in.link
还有一个搞笑的,大概是因为发明了万维网。很多人收到垃圾邮件时给 Tim Berners-Lee 发邮件吐槽。在这里他呼吁人们不要给他发这些邮件了。
最早的浏览器 图
现代浏览器架构系列 Inside look at modern web browser
Part1 浏览器进程
介绍了CPU、GPU、进程、线程的基本概念,以及 Chrome 采用的架构。
基本的架构模型是 浏览器进程(Browser Process) 协调 渲染进程(Renderer Process)、GPU进程(GPU Process)、插件进程(Plugin Process)等其它进程进行工作。
不同的硬件设备会有不同的进程线程模型。高端设备会创建多进程以便利用多核CPU,低端设备可能会创建多线程以节省内存。如网络相关的部分可能实现为网络进程,也可能是浏览器进程中的一个线程。
之前的 Chrome 版本中,每个 tab 一个独立的进程。 Chrome 67 之后,每个跨站的 iframe 也会创建一个渲染进程。Site Isolation
Part2 Navigation
介绍从输入 URL 到获取到页面数据,中间经历了哪些过程。
浏览器进程的线程:
处理模型:
Service Worker:
service worker is JavaScript code that runs in a renderer process.
当浏览器支持 Service Worker 时,在network thread 发起网络请求之前会检查该URL是否有注册 Service Worker。如果是,则找到一个 renderer Process 执行 Service Worker的代码。
Part3 渲染进程
介绍从解析 HTML、CSS、JavaScript 到渲染页面的过程。
渲染进程的线程:
基本流程:解析 HTML 生成DOM,遇到 script 等待 js 执行,解析 CSS。 匹配 DOM 和 CSS,生成 Layout Tree,Plaint,Composit。
Web Foundamental Performance 也有类似的介绍,性能优化上,可操作性更强。
一般场景:
JS / CSS > Style > Layout > Paint > Composite
JS或CSS 改变“layout” 的属性,比如元素的 width、height、定位元素的 left、top。
JS / CSS > Style > Paint > Composite
JS或CSS 改变“paint only”属性,比如background-image、color、shadow
JS / CSS > Style > Composite
animation 或 滚动
Web Foundamental Performance 系列下包含了在 chrome dev-tool 中分析绘制流程的方法,以及通用的优化手段。
Layout 是很耗时的一步,尽量减少。
Part4 事件处理
介绍用户触发的事件(click、keydown)是如何执行的。
基本处理流程:
浏览器进程监测到用户事件,将事件的类型和信息(如位置)传递给渲染进程
渲染进程中 compositor thread 会标记出一块可点击区域(Non-Fast Scrollable Region)。如果事件发生在区域外,compositor thread 直接生成新的 frame,如果事件发生在区域内,则将事件信息传递给 main thread.
main thread 根据事件的位置,找到 event target, 然后执行事件回调 js.
一些技巧与API
设备一般为 60 fps,即每秒绘制60次。但事件(如pointermove)触发的频率可能会比刷新频率高。Chrome 会合并事件,在 requestAnimationFrame 之前 dispatch。 通过 event.getCoalescedEvents() 可拿到合并的事件列表。(Chrome 70 测试 pointermove 可以拿到, mousemove 不行)
document.body 上进行事件代理时,添加 passive: true。 可避免阻塞 compositor thread
https://docs.google.com/presentation/d/1boPxbgNrTU0ddsc144rcXayGA_WF53k96imRH8Mp34Y/edit#slide=id.p
介绍了从网页代码到屏幕渲染出像素,以及页面样式变动重新渲染的过程。即 HTML + CSS + JavaScript --> pixel.
用户行为、动画、js等各种因素会触发页面内容的改变,或视窗内容的改变。此时需要重新渲染,为了提高性能,对 layout, paint, raster 等步骤做了更细的拆分和优化:
为了使页面动画流畅,需要达到 60FPS. 且每一帧应该是当前页面内容经过上述流程生成的位图。 为了减少不必要的重复步骤,可以根据当前页面内容的变化,跳过某些步骤,直接使用上次生成的中间数据。如只滚动页面,不需要重新 style 计算样式。
上述流程都使用主线程进行计算,而主线程还需要执行 js,可能造成页面卡顿。 将页面拆分为多个 layer,部分 LayoutObject 会导致生成一个 layer. 在其它线程(compositor thread)合成这些 layer.(某些样式属性会生成新的 layer.如transform,合成操作主要包括移动,裁切,缩放)
视窗外的部分没必要 raster compositor thread 将 layer 分成 tiles,然后交由多个 raster threads 处理。
Reading List