碎碎念
写在深夜,抬头看着月亮。感慨万分。一句话-心中有路,便有路直通远方。
浏览器多进程架构
我们都知道js是单线程的,那么浏览器多进程的架构我们可能不太熟悉,这里简述一下。
-
浏览器进程-主进程
- ui线程 - 控制ui,例如输入框、按钮
- 网络线程 - 负责资源下载
- 存储线程 - 负责本地缓存的访问
-
渲染进程-浏览器内核
- js线程 - js引擎,负责js的执行。
- 渲染线程 - 负责ui的渲染,和js线程互斥,一运行一挂起。
- 事件触发线程 - 负责事件管理,例如点击事件,该线程就负责把对应的任务添加到任务队列。
- 定时器线程 - 负责定时器的执行,例如setTimeout,其实就是BOM提供的一个接口。
- 异步资源请求线程 - 负责ajax请求,然后通过回调触发事件触发线程。
-
gpu进程-负责浏览器和gpu的通信
-
第三方插件进程-主要是浏览器插件运行进程
过程
请求行构建
ui线程把输入的url交给网络线程,网络线程构建请求行,浏览器准备发起请求。
请求行的格式: <请求方法> <请求路径> <协议>。
查找强缓存
什么是强缓存
强缓存其实就是存储在本地的资源-硬盘或者内存中,如果命中缓存,则直接使用缓存资源,如果没有则下一步。
强缓存方式
- expire 通过expire设置失效日期,与本地系统的时间对比,如果用户修改本地时间就可能导致缓存失效,这是一个缺点,所以就诞生了max-age。
- cache-control: 'max-age=' max-age优先级比expire优先级高,设置缓存多少秒失效。
DNS解析
域名其实就是ip地址的别名,为了让人们使用更方便。DNS解析其实就是把域名解析成ip地址。解析过程:
- 浏览器缓存,这里可以解答为什么301重定向后,不需要再访问旧地址再跳到新地址。
- 系统缓存,这里主要是hosts文件
- 根域DNS服务器
- 一级域名服务器
- 二级域名服务器
- ...
建立tcp连接
这里不做过多叙述,要明白几个点:
- 三次握手的过程
- 为什么要三次 建立tcp连接其实很耗时间的,所以诞生了很多优化方式,例如pre-connect等,优化方式,之后会再写一篇文章。
发送请求,接受响应
这里主要是在建立好的tcp连接中发送请求报文,以及接受响应报文。请求报文三部分组成:请求行,请求头、请求体。响应报文同理。
查找协商缓存
什么是协商缓存
协商缓存和强缓存的区别
协商缓存每次都要发起请求,然后服务器判断资源是否更新,如果没有更新则直接返回304,如资源更新了则直接返回资源,与cache-control:no-cache搭配使用。
强缓存则不需要每次都发起请求,通过expire或者max-age判断缓存是否失效,不失效则直接使用。
协商缓存的方式
last-modified
当初次请求时,服务端给响应头加last-modified:<修改时间>字段,当再次请求时浏览器会把last-modified的值加到if-modified-since上,服务端再根据该字段判断是否资源更新。
缺点
- 值粒度为秒,如果在1秒内修改资源,那么缓存还是不会更新的。
- 因为值时修改资源的时间,那么如果我只是修改资源,但这里修改没有修改内容,那么缓存失效。
ETAG
ETAG优先级比前者高,ETAG时内容签名,我们可以认为是根据内容生成的hash,当初次请求时,服务端给响应头加ETAG:字段,当再次请求时浏览器会把etag的值加到if-none-match上,服务端再根据该字段判断是否资源更新。 ETAG解决了前者的很多问题点。
tcp连接断开
这里不做过多叙述,要明白几个点:
- 四次挥手的过程
- 为什么要四次
渲染
生成dom tree
我们获取的是字节形式的html内容,所以我们要经过以下几步形成dom tree
- 字节按utf8编码成字符串
- 字符串词法分析,标记化
- 标记语法分析形成dom节点,包含节点的属性和规则
- 按节点之间的关系形成dom tree
生成cssom tree
与上一步同理,不过这里有几点要明白
- 属性转换,例如:blue -> RGBA,blue其实有点像指令集的助记符。
- 确定每个标签的最终样式
生成布局树
我们确定了每个节点-dom tree,以及每个节点的样式-cssom tree,接下来我们就要确定节点的几何属性,所以 dom tree + cssom tree 形成布局树,布局树要注意几点:
- display:none的元素不在布局树上
- 忽略head
生成图层树
我们要对特定的节点形成对应的图层,因此根据对应的规则+布局树形成图层树。为什么要形成对应的图层,个人推断应该防止渲染爆炸。这里的规则可以看一下MDN。这里不做过多描述。
生成绘制列表
把图层拆成一个个绘制指令,再按绘制顺序形成绘制列表。然后渲染主线程把绘制列表交给合成线程。
栅格化
栅格化其实就是合成线程把图层拆成图块,再把视口附近的图块转换成位图。
合成与显示
当栅格化完成后,合成线程发出drawquad命令,浏览器进程有个viz组件会监听,然后会把页面写入内存再显示到页面上,