一、浏览器原理和V8引擎

一.、从输入url到展示的过程

1.输入url

2.发起请求(URL解析/DNS解析)

3.网络连接(三次握手)

4.服务器响应请求,返回数据

5.浏览器加载/渲染页面

二、浏览器构成

image.png

1.User Interface(用户界面)

包括地址栏,前进/后退按钮,书签菜单等。除了显示你请求的页面外,其他显示的各个部分都属于用户页面

2.Browser engine(浏览器引擎)

在用户界面和渲染引擎之间传送数据

3.Rending engine(渲染引擎)

负责显示请求的内容,对于html,负责解析html和css内容,并将解析后的内容显示在屏幕上

4.Networking(网络)

用于网络调用,比如http请求,接口与平台无关,并为所有平台提供底层实现

5.JavaScript Interpreter(javascript解释器)

用于解析和执行javascript代码

6.UI Backend(UI后端)

用于绘制基本的窗口小部件,比如组合框和窗口,其公开了与平台无关的通用接口,而在底层使用操作的用户界面方法

7.Data Persistence(数据持久性)

这是持久层。浏览器需要在硬盘上保存各种数据,例如Cookie。新的HTML规范(HTML5)定义了“网络数据库”,这是一个完整(但是轻便)的浏览器内数据库。

三、浏览器内核

浏览器的主要功能就是向服务器发出请求,在浏览器窗口中展示您选择的网络资源。

浏览器的内核是指支持浏览器运行的最核心的程序,分为两个部分:

1.渲染引擎

2.JS引擎

四、浏览器加载/渲染页面——渲染引擎

image.png

1.解析HTMI为DOM树

html字节流变成字符流

词法分析:将字符流解析为一个个词语

语法分析:通过不同的标签生成node节点

构建DOM树:将node节点组织成DOM树

解析外部CSS文件及style标签中的样式信息,得到元素最匹配的样式:

1)经过词法分析和语法分析,生成一个CSS规则

2)进行规则匹配

2.渲染树结构

生成RenderObject树:由DOM树构建RenderObject树,并将CSS得到的元素匹配样式存入到RenderObject树中

3.布局渲染树

根据RenderObject中的样式属性,计算根据框模型,计算布局

4.绘制渲染树

先绘制元素背景,然后是浮动,最后是前景。最终得到用户可见区域(ViewPort)的内存表示

五、页面加载过程中HTML,CSS,JavaScript加载顺序

通常页面的加载速度会受HTML,CSS ,JS 的影响

  1. 浏览器接收到HTML模板文件,开始从上到下解析HTML

  2. 遇到样式表文件style.css,这时候浏览器停止解析HTML,接着去请求CSS文件

  3. 服务端返回CSS文件,浏览器开始解析CSS文件

  4. 浏览器解析完CSS,继续往下解析HTML,碰到DOM节点,解析DOM

  5. 浏览器发现img,向服务器发送请求。此时浏览器不会等到图片下载完,而是继续渲染后面的代码

  6. 服务器返回图片文件,由于图片占据了一定的面积,影响了页面排布,因此浏览器需要回过头来重新渲染这部分代码

    reflow(回流):当浏览器发现页面中某个部分发生了点变化影响了布局,需要倒回去重新渲染,这个过程为reflow

    repaint(重绘):改变某个元素的背景色,字体颜色,边框颜色等等不会影响布局的时候,屏幕的一部分呢需要重画,但是元素的布局不会发生变化

  7. 碰到脚本文件,这时停止所有的加载与解析,去请求脚本文件,并执行脚本

  8. 加载完所有的HTML,CSS,JS后,页面就出现在屏幕上了

渲染引擎会尽可能早的将内容呈现到屏幕上,并不会等到所有的html解析完后才去构建和布局render树。它是解析完一部分就下载一部分,同时还可能在下载别的内容

六、关于CSS阻塞和JS阻塞

1.CSS会阻塞渲染吗?

从浏览器的渲染原理来看,渲染引擎会将css构建成CSSOM Tree然后再去渲染页面,也就是说css会阻塞页面的渲染。

但是css不会阻塞页面的解析,因为需要具有DOM以及CSSOM才会构建渲染树-

2.JS会阻塞渲染吗?

加载或执行js代码时,会阻塞构建DOM树,只有等到js执行完毕,浏览器才会继续解析DOM。

没有DOM树,浏览器就无法渲染,所以当加载很大的JS文件时,可以看到页面很长时间时一片空白。

这是因为在加载js的过程中会操作DOM节点,这些操作会对DOM树产生影响,如果不阻塞,等浏览器解析完标签生成DOM树后,JS修改了某些节点,那么浏览器又得重新解析,然后重新生成DOM树,耗费性能

3.解决JS阻塞DOM树生成

defer 和 async 都是作用于外链JS的。对内部JS是没有效果的。

defer 和 async 都是异步的,主要的区别在于执行的顺序以及执行的时间

async 标志的脚本文件一旦加载完成后就会立即执行,并且不会按照书写顺序,谁下载好了就直接执行。所以适应于那些没有代码依赖顺序,并且没有DOM操作的脚本文件

defer 标志的脚本文件会严格按照书写顺序去执行,并且会在页面DOM加载完成时执行,适用于有DOM操作,或者是有代码依赖顺序的脚本文件。

七、JS代码由谁来执行呢?——JS引擎(比如V8引擎)

1.为什么需要JS引擎?

高级语言都是转成机器指令来执行的

我们编写的JavaScript代码无论交给浏览器还是Node,最终都会交给CPU来执行

但是CPU只认识自己的指令集,实际上是机器语言,才能被CPU执行

所以我们需要JavaScript引擎帮助我们将JavaScript代码翻译成CPU指令来执行

2.V8引擎

1)V8基本概念

V8是用C++编写的Google开源高性能JavaScript和WebAssembly引擎,它作用于Chrome和Node.js等,可以作用在很多系统上,可以独立运行,也可以嵌入到任何C++程序中

2)V8的架构

  • Parse模块会将JavaScript代码转为AST树(抽象语法树),这是因为解释器并不直接认识JavaScript代码。如果函数没有被调用,是不会转成AST的

  • Ignition是一个解释器,会将AST转为ByteCode(字节码)

    同时会收集TurboFan优化所需要的信息(比如函数参数的类型信息,有了类型才能进行真实的运算)

    如果函数只执行一次,Ignition会执行解释ByteCode

  • TurboFan是一个编译器,可以将字节码翻译为CPU直接执行的机器码

    如果一个函数被多次调用,那么就会标记为热点函数,那么就会经过TurboFan转化成优化的机器码,以后CPU直接运行机器码,提高代码的执行性能。

    但是,机器码也会还原为ByteCode,这是因为如果后续执行函数的过程中,类型发生了变化(比如sum函数原来是number类型,后来变为string类型),之前优化的机器码并不能正确的处理运算,就会逆向的转为字节码

3)V8引擎的解析图(官方)

[图片上传失败...(image-113b81-1645708377771)]

  • Blink将源码交给V8引擎,Stream获取到源码并且进行编码转换

  • Scanner会进行词法分析,词法分析会将代码转换成tokens

  • 接下来tokens会经过Preparser和Parser转换为AST树

    Parser就是直接将token转换为AST树架构

    Preparser称之为预解析,为什么需要与解析呢?

    <u style="box-sizing: border-box;">这是因为并不是所有的JavaScript代码,在一开始就会被执行,那么对的所有的JavaScript代码进行解析,必然会影响网页的效率</u>

    <u style="box-sizing: border-box;">所以V8引擎就实现了Lazy Parsering(延迟解析)的方案,它的作用是将不必要的函数进行与解析,也就是只解析暂时需要的内容,而对函数的全量解析是在函数被调用时才会进行</u>

    <u style="box-sizing: border-box;">比如我们在一个函数oute内部定义了另外一个函数inner,那么inner函数就会进行预解析</u>

  • 生成AST树后,会被Ignition转为字节码,之后的过程就是代码的执行过程(下一篇进行详细讲解)

备注:本文部分内容都来自coderwhy老师,感兴趣的小伙伴可以去简书或者github搜索coderwhy,会有很多收获-

参考链接:

1.https://www.jianshu.com/p/7401a240f21f

2.https://www.jianshu.com/p/4a942a7dc153

3.https://segmentfault.com/a/1190000017476386

4.coderwhy

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容