一、浏览器组成
1、对浏览器的理解?
浏览器是对web资源,如html,image等资源的展示,浏览器向服务器请求资源,展示在页面中。
HTML和CSS对浏览器解析html做了规范,规范由W3C(制定web标准的组织)进行维护。不过浏览器厂家对浏览器进行了扩展,所以没有完全按照规范来,就会有兼容不同浏览器的问题
浏览器由shell外壳和内核组成,shell种类相对很多,内核很少,在 Mozilla 将 Gecko 独立出来后,才有了外壳和内核的明确划分。
- shell外壳:菜单,工具栏等,给用户提供操作,参数设置等
- 内核:内核是浏览器的核心,实现各种功能,是基于标记语言显示内容的程序和模块
2、对浏览器内核的理解?
主要分成两部分:渲染引擎和 JS 引擎。
- 渲染引擎:就是渲染,在浏览器中显示所请求的内容。渲染引擎可以显示 html、xml 文档及图片,也可以借助插件(一种浏览器扩展)显示其他类型数据,例如使用 PDF 阅读器插件,可以显示 PDF 格式。
- JS 引擎:解析和执行 javascript 来实现网页的动态效果。最开始渲染引擎和 JS 引擎并没有区分的很明确,后来 JS 引擎越来越独立,内核就倾向于只指渲染引擎。
3、常见浏览器内核及区别?
- Trident :IE 浏览器 用的内核,因为早期 IE 占有大量的市场份额,所以这种内核比较流行,以前有很多网页也是根据这个内核的标准来编写的,但是实这个内核对真正的网页标准支持不是很好。但是由于 IE 的高市场占有率,微软也很长时间没有更新 Trident 内核,导致了 Trident 内核和 W3C 标准脱节 。还有就是 Trident 内核的大量 Bug 等安全问题没有得到解决,加上一些专家学者公开自己认为 IE 浏览器不安全的观点,使很多用户开始转向其他浏览器。
- Presto :Opera浏览器 曾经用的就是 Presto 内核,Presto 内核被称为公认的浏览网页速度最快的内核 ,这得益于它在开发时的天生优势,在处理 JS 脚本等脚本语言时,会比其他的内核快 3 倍左右 ,缺点就是为了达到很快的速度而丢掉了一部分网页兼容性
- Blink :chrome浏览器 内核,谷歌在 Chromium Blog 上发表博客,称将与苹果的开源浏览器核心 Webkit 分道扬镳,在 Chromium 项目中研发 Blink 渲染引擎(即浏览器核心),内置于 Chrome 浏览器之中。其实 Blink 引擎就是 Webkit 的一个分支 ,就像 webkit 是 KHTML 的分支一样。Blink 引擎现在是谷歌公司与 Opera Software 共同研发,Opera 弃用了自己的 Presto 内核,加入 Google 阵营,跟随谷歌一起研发Blink。
- Webkit :Webkit 是 Safari浏览器 用的内核,它的优点就是网页浏览速度较快 ,不及Presto 但是胜于 Gecko 和 Trident,缺点是对网页代码的兼容性较低,编写不标准的网页无法正确显示。WebKit 前身是 KDE 小组的 KHTML 引擎,可以说 WebKit 是 KHTML 的一个开源的分支。
- Gecko :Firefox 和 Flock 所采用的内核,这个内核的优点就是功能强大、丰富,可以支持很多复杂网页效果和浏览器扩展接口 ,缺点是显而易见就是要消耗很多的资源,比如内存
4、浏览器架构?
架构中是用户界面 ,界面中包含一个主线程 ,主线程中主要是内核 ,内核包括以下:juejin.cn/post/735493...
- GUI渲染引擎
- JS 引擎
- 执行栈
- 事件触发线程
- 消息队列
- 微任务
- 宏任务
- 消息队列
- 定时器线程
- 网络异步线程
5、IE 各版本和 chrome 可以并行下载多少个资源?
- IE:IE6 2个并发;IE7及之后 6个
- chrome、firefox:6个并发
二、浏览器渲染
1、浏览器渲染过程原理?
- 浏览器首先解析 收到的文档,会根据 html 文件构建 DOM 树
- 根据解析 到的 css 文件构建 CSSOM 树
- DOM 与CSSOM 会合成Render,构建渲染树,渲染树中的每个节点是渲染对象,渲染对象包含颜色和大小等属性,渲染对象与DOM元素相对应,但不是一对一的关系,可能一个DOM元素对应多个渲染对象,没有显示的DOM元素不会插入到渲染树中
- layout根据render计算好每个节点确切位置和大小,根据节点正确的显示到浏览器位置,根据渲染树来进行布局(也就是回流,DOM树中元素变化时 ),也叫自动重排
- Painting根据计算好的位置绘制页面,绘制是逐步完成的,为了更好的用户体验,渲染引擎会尽可能早的将内容呈现到屏幕上,并不会等到所有的 html 都解析完成之后再去构建和布局 render 树。它是解析完一部分内容就显示一部分内容,同时,可能还在通过网络下载其余内容。
2、浏览器渲染过程遇到js怎么处理?(解析过程)
js 的加载、解析与执行会阻塞文档的解析,在构建 DOM 时,HTML解析器要是遇到了js,它会暂停文档的解析,将控制权移交给 js 引擎,等 js 引擎运行完毕,浏览器再从中断的地方恢复继续解析文档。
如果想首屏渲染的越快,不应该在首屏加载 JS 文件,这也是建议将 script 标签放在 body 标签底部的原因。当然并不是说 script 标签必须放在底部,也可以给 script 标签添加 defer 或者 async
3、async 和 defer 的作用是什么?有什么区别?(解析过程)
在浏览器渲染过程中遇到js就会暂停document文档解析,先执行js,这样会阻塞文档的渲染。这时候可以加上defer和async
- defer :延迟执行引入的js。js加载过程与文档解析过程并行,当整个 document 文档解析完成后再执行js文件,在 DOMContentLoaded 事件触发之前完成。多个脚本按顺序执行。
- async :异步执行js文件,遇到js文件时会异步加载,与defer的区别是,async加载完后会立马执行js文件,如果文档还未解析完成,仍然会阻塞文档解析,只是加载不会阻塞。多个脚本的执行顺序无法保证。
4、什么是文档的预解析?(解析过程)
当执行 js 时,另一个线程解析剩下的文档,并加载后面需要通过网络加载的资源,Webkit 和 Firefox 都做了这个优化。这种方式可以使资源并行加载使整体加载速度更快。预解析并不改变 DOM 树,这个工作留给主解析过程,自己只解析外部资源的引用,比如外部脚本、样式表及图片
5、CSS如何阻塞文档解析?(解析过程)
CSS解析为CSSOM树不会阻塞文档解析,但是如果在js中有css的修改,如果样式还没有加载和解析,js会得到错误的值,导致很多问题。
如果CSSOM还没解析和构建完成,这时候想执行js脚本,浏览器会延迟执行js脚本和文档解析,直到CSSOM解析构建完成
6、渲染页面时常见哪些不良现象?(渲染过程)
- FOUS:fous是页面当开始显示一个样式,等加载完成后又显示另一个样式。主要是浏览器先加载出来HTML,样式突然加载出来,原因是css 加载时间过长,或者 css 被放在了文档底部
- 白屏:浏览器渲染机制先构建 DOM 树和 CSSOM 树,构建完成后再进行渲染,如果 CSS 部分放在 HTML 尾部,由于 CSS 未加载完成,浏览器迟迟未渲染,导致白屏;也可能是把 js 文件放在头部,脚本的加载阻塞后面文档的解析,从而导致页面未渲染出来,出现白屏问题。
7、如何优化关键渲染路径?(渲染过程)
- 减少关键资源数量: 关键资源是阻止首屏加载的资源,资源越少,浏览器工作量越小,对cpu及其他资源的占用越少
- 减少关键字节数量: 减少资源数(删除或者将他们设为非关键资源),可以压缩和优化各项资源,最大程度减小传送大小
- 减少关键路径的长度: 路径长度受关键资源和他对应的字节大小之间依赖图的影响,资源越大,下载所需的往返次数越多;有的资源只能在上一个资源下载完毕后再进行下载
优化关键渲染路径步骤:
- 分析关键路径资源数,字节数,路径长度
- 最大程度减少关键资源的数量:删除或者转为非关键资源,延迟下载,标为异步等等
- 优化关键字节数,缩短下载时间
- 尽早下载关键资源,以缩短关键路径长度
8、什么是重绘和回流?(绘制过程)
1. 回流(Reflow重排)
回流是DOM树发生变化,比如大小,布局,隐藏显示(v-if影响,display:none不会影响),影响布局的时候触发,回流会影响性能,应该减少回流的产生。
会导致回流的操作:
- 首次渲染
- 改变窗口大小
- 改变元素大小和位置
- 改变字体大小
- 添加删除可见的DOM元素
- 激活css伪类(如::hover)
- 查询某些属性或者调用某些方法
常用且会导致回流的属性和方法:
clientWidth
、clientHeight
、clientTop
、clientLeft
offsetWidth
、offsetHeight
、offsetTop
、offsetLeft
scrollWidth
、scrollHeight
、scrollTop
、scrollLeft
scrollIntoView()
、scrollIntoViewIfNeeded()
、scrollTo()
getComputedStyle()
getBoundingClientRect()
2. 重绘(Repaint)
重绘是DOM中的样式(color、background-color等)发生变化,不会影响布局。
3. 性能
回流一定会重绘,重绘不一定会回流,回流的代价比重绘高很多
现代浏览器对于重绘和回流有一定的优化:
- 会将重绘和回流的操作放到一个线程中,等到了一定的数量或者是时间到了一定的阔值,就会进行批量操作,将这些重绘和回流进行一次性操作,但是发生以下属性方法时会立马清空进行操作
触发清空的属性和方法:
clientWidth
、clientHeight
、clientTop
、clientLeft
offsetWidth
、offsetHeight
、offsetTop
、offsetLeft
scrollWidth
、scrollHeight
、scrollTop
、scrollLeft
getComputedStyle()
getBoundingClientRect()
width
、height
9、如何减少回流?(绘制过程)
CSS:
- 对于动画效果:添加到position是
absolute
绝对定位或者fixed
元素上,使它脱离文档流,否则会引起父元素及后续元素频繁回流。 - 避免使用
table
布局:对Render Tree
的计算通常只需要遍历一次就可以完成,但table
及其内部元素除外,他们可能需要多次计算,通常要花同等元素3倍的时间 - 避免使用多层内联样式
- 避免使用
css表达式
(如:calc()
) - 可以先为元素设置
display: none
,操作结束后再把它显示出来。因为在display
属性为none
的元素上进行的DOM
操作不会引发回流和重绘。
js:
避免频繁操作DOM
:使用片段documentFragment一次性操作DOM,避免频繁操作js中样式
:可以使用class进行一次性更改- 减少使用引起重绘回流的属性和方法,如果需要使用多次,使用一个变量缓存起来
避免节点属性值放在循环中
,可以存入到变量中
10、为什么操作 DOM 慢?(绘制过程)
一些 DOM 的操作或者属性访问可能会引起页面的回流和重绘,从而引起性能上的消耗。
11、对浏览器渲染优化?
1. js方面
- js放body后面
- body中间尽量不要写
<script>
- 使用
<script>
有三种方法:直接写;添加defer;使用async,使用defer或者async
2. css方面:使用CSS有三种方式:使用link、@import、内联样式,link和@import都是导入外部样式。
它们之间的区别:
- link:浏览器会派发一个新的线程(HTTP线程)去加载资源文件,与GUI渲染线程同时向下渲染代码
- @import:GUI渲染线程会暂停渲染,去服务器加载资源文件,文件没有返回之前不会继续渲染(阻碍浏览器渲染)
- style:GUI直接渲染
外部样式如果长时间没有加载完毕,浏览器为了用户体验,会使用默认样式,确保首次渲染的速度。所以CSS一般写在header中,让浏览器尽快发送请求去获取css样式。
所以,在开发过程中,导入外部样式使用link,而不用@import。如果css少,尽可能采用内嵌样式,直接写在style标签中。
3. DOM树和CSSOM树方面
- 减少html层级深度,使用语义化标签,更好的识别标签
- 减少css层级关系,css层级关系是从右向左解析,这样可以减少遍历匹配次数