1.组件1.用户界面(UserInterface)用户界面主要包括工具栏、地址栏、前进/后退按钮、书签菜单、可视页面加载进度、智能下载处理、Preferences、Printing等。请求的页面,所有其他显示的部分都属于用户界面。2、渲染引擎(RenderingEngine)主要用于渲染静态资源(html、css、图片等),可以准确计算出页面布局,可以使用“回流”、“重绘”逐步调整页面位置元素(例如chrome浏览器闪烁,旧版本的webkit)。3.Js引擎(JavaScript解释器)以v8引擎为例,首先读取js源码,使用parse解析器将JavaScript代码转换成AST(抽象语法树),然后通过Ignition解释器,AST将被转换成字节码(bytecode)输出。4.网络(Networking)是用于完成网络调用或资源下载的模块,基于TCP协议,如HTTP、Websocket。(太长,后面会细说)6.显示后端(DisplayBackend)显示后端提供绘图和窗口图元,包括:用户界面控件集合,字体集合。7.数据持久化(DataPersistence)管理用户数据,例如书签、cookies和偏好。(太长了,后面再说)2、加载资源的顺序和过程首先,我们要知道里面有哪些资源:htmlcssjs字体、图片、ajax(api接口请求)……其次,我们需要了解加载过程:这个比较重要,比较容易混淆需要挑出来,就是dom、css、js的顺序。分为三类进行讨论:1.dom和css外链样式:两者的加载是异步的,互不干扰。但是CSS的加载会阻塞DOM渲染,因为DOM渲染只有在DOM树和CSSOM树合并成一棵渲染树后才能进行。(这里要区分渲染和加载的区别)内联样式和内联样式:内联样式是DOM中节点的样式属性,内联样式是样式标签包裹的形式,所以前者是节点,后者是一个label,它们将在dom加载时作为dom的一部分加载。2.dom和js外链js:加载js文件时,会阻塞dom的加载。如果加载js时间过长,会导致页面显示滞后,出现“假死”状态。如果在head内外链中导入js,在js中操作dom的话,会获取不到dom,会出现异常。这也是为什么我们一般会把js代码写在onloadhook里面,而js的导入一般都放在文档的最后。(题外话:defer,async属性可以手动控制这种情况)内联js:从上到下按顺序加载,读取script标签包裹的js代码,立即执行,执行中,阻塞dom加载,执行完,继续下载。3.css和js有一个特例。如果在JS中访问CSSDOM中某个元素的样式,那么需要等待样式加载完毕,再继续执行JS脚本。当然,恰恰相反,两者是相互独立的。总结:html>css>font>图片js>ajax>prefetch(预加载资源)(一般顺序也可以手动控制)三、工作原理1、获取url,DNS服务器域名解析成ip地址2.建立TCP连接,三次握手第一次握手:客户端应用进程主动打开并向服务器发送请求(即:发送方向接收方发送带有SYN标签的数据包)第二次握手:服务器应用进程是被动打开,如果同意客户端的请求,则返回确认信息(即接收端收到数据包后,会返回一个带有SYN/ACK标志的数据包给发送端确认)。第三次握手:客户端收到确认报文后,通知上层应用进程连接已经建立,并向服务器端发送确认报文。服务器在收到客户端的请求后,也会通知其上层应用进程连接已经建立。(最后,发送方向接收方返回一个带有ACK标志的数据包,代表“握手”结束)3.请求静态资源并按规则加载(2.加载资源顺序及流程),domtree和css规则树被集成到rendertree中。layout布局完成后,在页面绘制ui后台(加载和渲染同时进行)。遇到js解析时,由js解析引擎完成(这里涉及到js的事件循环机制和Single-threaded,详见下文js的执行机制)。4、断开http连接,挥手四次,第一次挥手:客户端应用发送连接释放消息,停止发送数据。第二次挥手:服务器收到连接释放报文后,发送确认报文。此时连接处于半关闭状态,客户端不再继续向服务器发送数据,而是服务器继续向客户端发送数据。第三次挥手:如果服务器端没有数据发送给客户端,应用进程会通知服务器端释放TCP连接。第四次挥手:客户端收到发布消息后必须确认。2MSL(MaximumMessageLifetime)s后,这个TCP连接正式结束。4.回流和重绘以及如何避免重绘:渲染树中的一些元素需要更新属性,而这些属性只影响元素的外观和样式,不影响布局。场景:元素的展示;元素大小变化(包括外边距、外边距、边框大小、高度和宽度等);内容变更;页面首次呈现;浏览器窗口大小变化Reflow:渲染树中部分(或全部)场景因元素大小、布局、可见性等发生变化需要重新构建:背景颜色、字体颜色等如何实现避免不改变结构布局的样式改变:1.使用分片文档documenFragment,合并多次一次性渲染2.避免直接修改样式,修改类名3.脱离文档流当然,大多数浏览器都进行了自己的优化——渲染队列。浏览器会将所有的回流和重绘放入一个队列中。当达到一定数量或一定间隔时,浏览器将对队列进行批处理。这样做的目的是改变一次多次,减少重绘和回流的次数。5、JS执行机制JS是单线程的,自上而下解析执行。当遇到同步任务时,会放到主线程中依次正常执行。当遇到异步任务时,会放入事件表中,并将其一对一映射到一个函数。当满足触发条件时,会被推入事件队列。当主线程空闲时,它会去事件队列中检查是否有可执行的异步任务。如果是这样,它将被推入主线程。在线程中,js的执行机制也叫事件循环。如何判断多个异步任务的执行顺序:异步任务分为宏任务和微任务宏任务:script、setTimeout、setInterval、postMessage、MessageChannel、setImmediate(Node.js环境)。微任务:Promise.then、Object.observe、MutationObserver、process.nextTick(Node.js环境)。先执行同步代码,遇到异步宏任务时将异步宏任务放入宏任务队列,遇到异步微任务时将异步微任务放入微任务队列,当同步代码全部执行完毕,则把异步的微任务从队列中转移到主线程执行。微任务执行完毕后,异步宏任务从队列中转移到主线程执行,如此循环直到所有任务执行完毕。
