web游览器原理部分(通俗易懂)

一、浅谈对游览器的理解

我认为游览器的主要功能是将用户选择的web资源呈现出来,它需要从服务器请求资源,并且显示在游览器的窗口。游览器可以分为两个部分:shell与内核
shell的种类相对较多,内核就相对较少。shell指的是游览器的外壳,例如:菜单,工具栏等,主要是为用户提供界面操作。它是通过调用内核来实现各种功能。
内核才是游览器的核心,内核是基于标记语言显示内容的程序和模块。
简单来说,内核分为渲染引擎与JS引擎。渲染引擎的职责就是渲染在游览器窗口显示所请求的内容。默认情况可以渲染html,xml文档和图片,也可以借助插件显示其他类型数据。JS引擎是来解析和执行javascript来实现网页的动态效果。
最开始渲染引擎和JS引擎没有多大区分的很明确,后来JS引擎越来越独立,内核就倾向于只指渲染引擎。

二、游览器的渲染原理

关于游览器渲染原理,我认为是这样的一个流程。首先解析收到的文档,根据文档生成一颗DOM树,DOM树是由DOM元素和它的属性节点构成。然后对CSS文件进行解析,生成CSSOM规则树,然后根据DOM树与CSSOM规则树构建渲染树,渲染树的节点被称为渲染对象,渲染对象与DOM元素结点相对应,但不是一对一的关系,不可见的DOM元素不会被插入渲染树。然后根据渲染树进行布局,就是确定渲染树的各个结点在页面的确切位置,然后就可以渲染,遍历渲染树并调用渲染对象的paint方法将内容显示在屏幕上,绘制使用UI基础组件。还有一点是,为了保障更好的用户体验,并不会等到所有html解析完才去布局渲染,而是解析完一部分就显示一部分内容,与此同时,可能还在通过网络下载其余内容。

三、游览器解析过程async与defer的作用与区别

1、脚本没有defer或者async的时候,游览器会立即加载并执行指定脚本,也就是不等待后续载入的文档元素,读到就加载并执行。
2、defer 属性表示延迟执行引入的 JavaScript,即这段 JavaScript 加载时 HTML 并未停止解析,这两个过程是并行的。当整个 document 解析完毕后再执行脚本文件,在 DOMContentLoaded 事件触发之前完成。多个脚本按顺序执行。
3、async 属性表示异步执行引入的 JavaScript,与 defer 的区别在于,如果已经加载好,就会开始执行,也就是说它的执行仍然会阻塞文档的解析,只是它的加载过程不会阻塞。多个脚本的执行顺序无法保证。

四、游览器解析过程之文档预解析

当执行 JavaScript 脚本时,另一个线程解析剩下的文档,并加载后面需要通过网络加载的资源。这种方式可以使资源并行加载从而使整体速度更快。需要注意的是,预解析并不改变 DOM 树,它将这个工作留给主解析过程,自己只解析外部资源的引用,比如外部脚本、样式表及图片。

五、游览器渲染之不良现象

FOUC(无样式内容闪烁):主要指的是样式闪烁的问题,由于浏览器渲染机制(比如firefox),在 CSS 加载之前,先呈现了 HTML,就会导致展示出无样式内容,然后样式突然呈现的现象。会出现这个问题的原因主要是 CSS 加载时间过长,原因是CSS 被放在了文档底部或者通过import导入。
解决办法:换做使用LINK标签将样式表放在文档HEAD中来引入css样式,在标签里面引用CSS.。
白屏:有些浏览器渲染机制(比如chrome)要先构建 DOM 树和 CSSOM 树,构建完成后再进行渲染,如果 CSS 部分放在 HTML 尾部,由于 CSS 未加载完成,浏览器迟迟未渲染,从而导致白屏;也可能是把 JS 文件放在头部,脚本的加载会阻塞后面文档内容的解析,从而页面迟迟未渲染出来,出现白屏问题。
解决办法
1.减少DOM树渲染的时间(HTML层级不要太深,标签语义化…)
2.减少HTTP请求次数和请求大小
3.把CSS放在Head中,将js放在body的最后,避免阻塞
4.使用ssr渲染和预渲染。

客户端渲染:用户访问 url,请求 html 文件,前端根据路由动态渲染页面内容。关键链路较长,有一定的白屏时间;

服务端渲染(ssr):用户访问 url,服务端根据访问路径请求所需数据,拼接成 html 字符串,返回给前端。前端接收到 html 时已有部分内容;

预渲染:构建阶段生成匹配预渲染路径的 html 文件(注意:每个需要预渲染的路由都有一个对应的 html)。构建出来的 html 文件已有部分内容。

六、游览器绘制之重绘与回流

重绘: 当渲染树中的一些元素需要更新属性,而这些属性只是影响元素的外观、风格,而不会影响布局的操作,比如 background
-color,我们将这样的操作称为重绘。
回流:当渲染树中的一部分(或全部)因为元素的规模尺寸、布局、隐藏等改变而需要重新构建的操作,会影响到布局的操作,这样
的操作我们称为回流。
回流必定会发生重绘,重绘不一定会引发回流。回流所需的成本比重绘高的多,改变父节点里的子节点很可能会导致父节点的一系列回流。
如何减少回流:
1.尽量使用css属性简写:如:用boder代替boder-width,boder-style,boder-color

2.批量修改元素样式 elem.className

3.尽量避免用table布局(table元素一旦触发回流就会导致table里所有的其它元素回流)

4.需要创建多个DOM节点时,使用DocumentFragment创建。

因为:每次创建一个页面就会发生回流,所以采用DocumentFragment批量创建

5.尽量不写css表达式。因为每次调用都会重新计算值(包括加载页面)

猜你喜欢

转载自blog.csdn.net/m0_59722204/article/details/128758655