浏览器如何运作

·  阅读 200
浏览器如何运作

为什么要了解浏览器工作原理?

写出更好的代码和提供更好的用户体验

浏览器结构

  • 用户界面
  • 浏览器引擎
  • 渲染引擎(可以说是一个浏览器的核心,我们往往称之为浏览器内核)

如下以chrome为例介绍浏览器运行原理

浏览器是运行在操作系统上的一个应用程序,每个应用程序至少启用一个进程来执行其功能,每个进程往往要执行很多任务,进程就会创建一些线程来执行小的任务

  • 进程是操作系统进行资源分配和调度的基本单元,可以申请和拥有计算机资源,进程是程序的基本执行实体
  • 线程是操作系统能够进行运行调度的最小单位,一个进程中可以并发多个线程,每条线程并行执行不同的任务
  • 当我们启动某个程序时,就会创建一个进程来执行任务代码,同时会为该进程分配内存空间,该应用程序的状态都保存在该内存空间里。当应用关闭时,该内存空间就会被回收。
  • 进程可以启动更多的进程来执行任务,由于每个进程分配的内存空间是独立的,如果两个进程间需要传递某些数据,则需要通过进程间通信管道IPC来传递。
  • 很多应用程序都是多进程的结构,这样是为了避免某一个进程卡死,由于进程间相互独立,这样不会影响到整个应用程序。
  • 同一进程下的线程之间是可以直接通信共享数据的。

现代浏览器采用了多进程浏览器结构

  • 浏览器进程负责与浏览器的其他进程协调工作

  • 网络进程负责发起接受网络请求,GPU进程负责图形渲染,插件进程负责控制网站使用的所有插件,例如Flash

  • 渲染器进程用来控制显示tab标签内的所有内容,浏览器在默认情况下会为每个标签页都创建一个进程

浏览器渲染原理

  • 当你在地址栏输入地址时,浏览器进程的UI线程会捕捉你的输入内容,如果访问的是网址,则UI线程会启动一个网络线程来请求DNS进行域名解析接着开始连接服务器获取数据。

  • 如果你的输入不是网址而是一串关键词,浏览器就会知道你是要搜索,于是就会使用你默认配置的搜索引擎来查询。

  • 当网络线程获取到数据后,会通过SafeBrowsing来检查该站点的是否是恶意站点。如果是则会展示个警告页面,告诉你这个站点有安全问题,浏览器会阻止你的访问。当然你也可以强行继续访问。SafeBrowsing是谷歌内部的一套站点安全系统,通过检测该站点的数据来判断是否安全。比如通过查看该站点的ip是否在他们的黑名单内。

  • 当返回数据准备完毕并且安全校验通过,网络线程会通知UI线程,然后UI线程会创建一个渲染器进程来渲染页面。浏览器进程通过IPC管道将数据传递给渲染器进程,正式进入渲染流程。

  • 渲染器进程的核心任务就是把html、js、css、img等资源渲染成用户可交互的web页面。

  • 渲染器进程的主线程将html进行解析,构造DOM数据结构。DOM文档对象模型是浏览器对页面在其内部表示形式。HTML首先经过Tokeniser标记化,通过词法分析,将输入html内容解析成多个标记,根据识别后的标记进行DOM树构造, 在 DOM树构造过程中会创建Document对象,然后以Document为根节点的DOM树不断进行修改,向其中添加各种元素。

  • HTML代码中往往会引入一些额外的资源,比如图片,css和js脚本等。图片和css这些资源需要通过网络下载或者从缓存中直接加载。这些资源不会阻塞html的解析,因为他们不会影响DOM的生成,但当html解析过程中遇到script标签,将停止html解析流程,转而去加载解析并且执行js,浏览器不知道js的执行是否会改变当前页面的html的结构,如果js代码了调用document.write方法来修改html,那之前的html的解析就没有任何意义了。这也就是为什么我们一直说要把script标签要放在合适的位置,或者使用async 或defer属性来异步加载执行js。

  • 在html解析完成后,我们就获得一个dom tree,主线程通过遍历DOM和计算好的样式来生成layout tree,layout tree上的每个节点都记录x,y坐标和边框尺寸。这里需要注意的一点是DOM Tree和layout tree并不是一一对应的,设置了display:none的节点不会出现在layout tree上,而在before伪类中添加了content值的元素,content的内容会出现在layout tree,不会出现在DOM树里。这是因为DOM 是通过html解析获得,并不关心样式。而layout tree是根据dom tree和计算好的样式来生成,layout tree是和最后展示在屏幕上的的节点是对应的。

  • 随着不断的优化升级,现在的Chrome使用了一种更复杂的栅格化流程,叫做compositing组合。Compositing是一种将页面的各个部分分成多个图层,分别对其进行栅格化并在合成器线程compositor thread的单独线程中进行合成页面的技术。简单来说就是,页面所有的元素按照某种规则进行分图层,并把图层都栅格化好了,然后只需要把可视区的内容组合成一帧展示给用户即可。

  • 浏览器进程的网络线程请求获取到html数据和通过IPC将数据传给渲染器进程的主线程,主线程讲html解析构造DOM树,然后计算样式,根据DOM树和样式生成layout Tree,通过遍历layout tree生成绘制顺序表,然后主线程将layout Tree和绘制顺序信息一起传给合成器线程,合成器线程按规则进程分图层,并把图层分为更小的图块传给栅格线程进行栅格化,栅格化完成后,合成器线程会获得栅格线程传过来的"draw quads"图块信息,根据这些信息,合成器线程合成了一个frame,然后将该合成frame通过IPC传回给浏览器进程,浏览器进程在传到GPU进行渲染,最后就展示到你的屏幕上了。

  • 当我们改变一个尺寸位置属性时,会重新进行样式计算,布局,绘制,以及后面的所有流程。这种行为我们称为重排。当我们改变某个元素的颜色属性时,不会重新触发布局,但还是触发会样式计算和绘制,这个就是重绘。我们可以发现重排和重绘会占用主线程,js的运行也是在主线程。

  • 如果你们写了个不断导致重绘重排的动画,浏览器则需要在每一帧都会运行样式计算、布局和绘制的操作,我们知道当页面以每秒大于60帧的刷新率,才不会让用户感觉到页面卡顿。

  • 如果你在运行动画时,还有大量的js任务需要执行,因为布局绘制和js的执行都是在主线程运行的,当在一帧的时间内,布局和绘制结束后,还有剩余时间,js就会拿到主线程的使用权,如果js执行时间过长就会导致在下一帧开始时,js没有及时归还主线程,导致下一帧动画没有按时渲染,就会出现页面动画的卡顿。

  • 可以通过requestAnimationFrame这个api来帮助我们解决这个问题。requestAnimationFrame这个方法会在每一帧被调用,通过这个api的回调参数,我们可以知道每一帧当前还剩余的,我们可以把js运行任务分成一些小块,在时间用完前,归还主线程

  • css中有个动画属性叫transform,通过该属性实现的动画,不会经过布局和绘制,而是直接运行在Compositor和rasterizing线程中,所以不会受到主线程中js执行的影响。更重要的是transform的动画,由于不需要经过布局绘制样式计算,所以节省了很多运算时间。可以让复杂的动画更加流畅。

参考资料

浏览器是如何运作的?

分类:
前端
标签:
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改