浏览器
# 1. 进程和线程
查看答案
在计算机原理中,有两个概念 进程 和 线程
- 进程:CPU资源分配的最小单位
- 线程:CPU调度的最小单位
进程有独立资源,并且可以协同多个线程去完成任务。线程是和其他线程协同合作,资源共享。
举例:各个小区,有自己的居委会和防疫物资,还有很多工作人员。小区就是一个进程,有自己的资源,可以独立分配资源,那些工作人员就是线程,可以共享进程中的资源,共同协作。
# 2. JS执行原理
查看答案
JS运行环境通常分为两种 Memory Heap(储存堆) 和 Call Stack(执行栈)
- Memory Heap是用来分配内存的,包括可执行的文件和语句,都会分配内存存放在一个具体的位置。
- Call Stack是用来执行回调的。
定时器、异步HTTP请求、事件触发这些在应用侧统称为WebAPI,有DOM、AJAX、setTimeout等。
而Web API会通过事件触发引擎会和执行堆栈(Memory Heap和Call Stack)进行沟通。
# 3. 浏览器,chrome中新开一个窗口,tab页是进程还是线程?
查看答案
进程
从区别概念上出发:进程是不会共享资源的,线程是一个共享资源的。tab页之间是不会共享资源的,所以是进程。A页面死循环了,B页面依旧可以正常运行。
# 4. 窗口(进程)间的通信
查看答案
storage,cookie
考察浏览器存储,可以延伸至多种存储的区别,以及应用的存储。
# 5. 单个浏览器的进程有哪些线程?
查看答案
浏览器有多个浏览器页面,其中的线程有:GUI渲染引擎,JS引擎,定时器触发引擎、异步HTTP请求线程,事件触发引擎以及其他
(chrome的V8里面还有一些特有的引擎,导入页面,3D加速...)
- GUI渲染引擎
- 解析模板、样式去构建DOM树 => 布局计算 => 绘制
- 与JS引擎互斥,当JS引擎执行时,GUI会pending,当 任务队列 空闲时,才会继续执行GUI
- JS引擎
- 处理js,解析并执行脚本
- 分配、处理、执行待执行的事件, event队列
- 阻塞GUI渲染
- 定时器触发引擎
- 异步定时器处理与执行 - **setTimeout和setInterval
- 接收JS分配的定时器任务,并计数
- 接收完成后交于事件触发线程触发
- 异步HTTP请求线程,也称为通信I/O线程
- 异步执行请求类处理:Promise/ajax等
- 接收JS引擎分配的异步HTTP请求
- 监听回调,交给事件触发线程触发
- 事件触发引擎
- 接收来源:定时器触发引擎,异步HTTP请求引擎和用户操作I/O
- 将回调过来的事件依次接入到 任务队列 的队尾,交给JS引擎
# 6. 为什么JS阻塞之后会白屏,内容无法渲染?
与JS引擎互斥,当JS引擎执行时,GUI会pending,当 任务队列 空闲时,才会继续执行GUI。
# 7. 浏览器渲染机制
查看答案
浏览器采用流式布局模型(Flow Based Layout)。
- 浏览器会把 HTML 解析成 DOM,把 CSS 解析成 CSSOM
- DOM 和 CSSOM 合并就 产生了渲染树(Render Tree)
- 有了 RenderTree,我们就知道了所有节点的样式,然后计算他们在页面上的大小和位置
- 最后把节点绘制到页面上。
由于浏览器使用流式布局,对 Render Tree 的计算通常只需要遍历一次就可以完 成,但 table 及其内部元素除外,他们可能需要多次计算,通常要花 3 倍于同 等元素的时间,这也是为什么要避免使用 table 布局的原因之一。
# 8. 说一下浏览器请求到html文件之后,渲染页面的过程
查看答案
# 解析HTML为DOM树
构建DOM树的时候是边下载边解析,并不是等html文件全部下载完了再去解析html,这样会比较节省时间。
# 解析CSS为CSSOM树(与上述并行)
解析到了html头部的时候,发现有css文件,此时下载css,css也是一边下载一边解析的,构建的是CSSOM树。
当DOM树和CSSOM树全部构建完毕之后,浏览器会把DOM和CSSOM树渲染成Render树。
# DOM+CSS生成Render树进行绘图
构造渲染树是进行样式计算,DOM树和CSS树有了之后,浏览器开始样式计算,主要是为DOM树上的节点找到对应的样式。
构建布局树:样式计算完之后就开始构建布局树,主要为DOM树上的节点找到页面上对应位置以及一些display:none元素的隐藏。
构建分层树:利用光栅找到视图窗口下对应的位图,主要是因为一个页面可能有几屏那么长,一下渲染出来比较浪费时间,所以浏览器会找到视图窗口对应的图块,将这部分的图块进行渲染。
最终渲染进行将整个页面渲染出来,在渲染过程中还会出现重排和重绘。
# 加载script中的js文件
js文件要放在body最下面
# 执行js
# 9. js文件和css文件引入位置对页面加载速度的影响
查看答案
css位置:渲染树的构成必须要和DOM树和CSSOM树一起才可以,所以尽快的构建CSSOM树是一个重要的优化手段,如果CSS文件放在尾部,整个加载过程就变成了一个串行的,现解析DOM,再解析CSS,所以一般css一般会放在头部<head >
中,这样就可以并行构建了。
js的位置:由于js的运行会阻止DOM树的渲染,所以如果js放在了头部,而且也没有异步加载的措施的话,js的运行就会打断DOM树的构建,那么页面就会出现白屏。所以文件要放在尾部,并不是说放在尾部就不会有问题,只是问题相对白屏要小,js如果文件较大,在代码加载过程可能会出现页面不可点击不可操作,不过体验上要比白屏要好一点。
而且,如果js中有对DOM的操作,如果放在头部,DOM树还没有构建完成,就会出现报错或者崩溃。
# 10. CSS的加载会造成阻塞么?
查看答案
DOM和CSSOM通常是并行构建,所以css的加载「不会阻塞Dom的解析」。
但是,由于Render树依赖DOM树和CSSOM树的,所以Render树必须等待CSSOM树构建完成,才能开始渲染,所以CSS加载「会阻塞Dom的渲染」;
由于js是可以操作DOM和CSS样式的,当在js中操作css时,如果在修改元素属性同时渲染页面,那么可能导致渲染前后获得的元素数据不一致,因此,为了防止出现此问题,浏览器的渲染和js的运行为互斥关系。所以,js的运行会在css执行完毕之后运行,所以css会「阻塞js的运行」
# 11. 重绘和回流(Repaint & Reflow),以及如何进行优化?
查看答案
# 重绘
- 由于节点的几何属性发生改变或者由于样式发生改变而不会影响布局的,称为重绘。
- 例如 outline, visibility, color、background-color 等
- 重绘的代价是高昂的, 因为浏览器必须验证 DOM 树上其他节点元素的可见性。
# 回流
- 是布局或者几何属性需要改变就称为回流。
- 回流是影响浏览器性能的关键因素,因为其变化涉及到部分页面(或是整个页面)的布局更新。
- 一个元素的回流可能会导致了其所有子元素以及 DOM 中紧随其后的节点、祖先节点元素的随后的回流。
- 回流必定会发生重绘,重绘不一定会引发回流。
# 优化
# 1. 避免频繁使用刷新浏览器渲染队列的属性
现代浏览器大多都是通过队列机制来批量更新布局,浏览器会把修改操作放在队列中,至少一个浏览器刷新(即 16.6ms)才会清空队列,但当你获取布局信息的时候,队列中可能有会影响这些属性或方法返回值的操作,即使没有,浏览器也会强制清空队列,触发回流与重绘来确保返回正确的值。
主要包括以下属性或方法:
- offsetTop、offsetLeft、offsetWidth、offsetHeight
- scrollTop、scrollLeft、scrollWidth、scrollHeight
- clientTop、clientLeft、clientWidth、clientHeight
- width、height
- getComputedStyle()
- getBoundingClientRect()
所以,我们应该避免频繁的使用上述的属性,他们都会强制渲染刷新队列。
# 2. css
- 使用 visibility 替换 display: none ,因为前者只会引起重绘,后者会引发回流。
- 避免使用 table 布局,可能很小的一个小改动会造成整个 table 的重新布局。
- 尽可能在 DOM 树的最末端改变 class,可以限制了回流的范围,使其影响 尽可能少的节点。
- 避免设置多层内联样式,CSS 选择符从右往左匹配查找,避免节点层级过多。我们应该尽可能的避免写过于具体的 CSS 选择器,然后对于 HTML 来说也尽量少的添加无意义标签,保证层级扁平。
- 避免使用 CSS 表达式,可能会引发回流。
- 将频繁重绘或者回流的节点设置为图层,图层能够阻止该节点的渲染行为影响别的节点,例如 will-change、video、iframe 等标签,浏览器会自动将该节点变为图层。
- 将动画效果脱离文档流,应用到 position 属性为 absolute 或 fixed 的元素上,避免影响其他元素的布局,这样只是一个重绘而不是回流,同时控制动画速度可以选择 requestAnimationFrame。
- 使用 transform 替代 top 等进行布局。
- CSS3 硬件加速(GPU加速),使用 css3 硬件加速,可以让 transform、opacity、 filters 这些动画不会引起回流重绘 。但是对于动画的其它属性,比如 background-color 这些,还是会引起回流重绘的,不过它还是可以提升这些动画的性能。
# 3.js
- 避免频繁操作样式,最好一次性重写 style 属性,或者将样式列表定义为 class 并一次性更改 class 属性。
- 避免频繁操作 DOM,创建一个 documentFragment,在它上面应用所有 DOM 操作,最后再把它添加到文档中。
- 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。
# 笼统的回答:
引发重排的操作有:
- 窗口,字体大小
- 增加样式
- 内容变化
- class属性变化
- 等等
引发重绘的操作有:
- 改变文字颜色
- 改变颜色背景颜色
- 等等
【避免/减少重排和重绘的方法】:
- 减少js对样式的操作,尽量使用css完成样式操作;
- 减少对dom的操作
- 在不得已使用js操作样式时,尽量合并多次操作;
- 图片指定宽高,尽量不写不指定宽高的元素
- 等等
# 12. 为什么有时候⽤translate来改变位置⽽不是定位?
查看答案
- translate 是 transform 属性的⼀个值。改变transform或opacity不会触发浏览器重新布局(reflow)或重绘(repaint),只会触发复合(compositions)。⽽改变绝对定位会触发重新布局,进⽽触发重绘和复合。
- transform使浏览器为元素创建⼀个 GPU 图层,但改变绝对定位会使⽤到CPU。 因此translate()更⾼效,可以缩短平滑动画的绘制时间。
- translate改变位置时,元素依然会占据其原始空间,绝对定位就不会发⽣这种情况。