前言
一、资源查找
从输入URL到页面展示的过程:
- 输入网址
DNS解析,获取IP地址- 发起
TCP连接,三次握手 - 发送
HTTP请求 - 服务器
处理请求并返回HTTP报文 - 浏览器解析
渲染页面 - 连接结束
二、浏览器下载资源
三、浏览器内核
浏览器内核指的是浏览器的排版引擎(layout engine)。也称浏览器引擎(browser engine),页面渲染引擎(rendering engine)。
不同浏览器由不同的内核组成:
Gecko:早期被Netscape和Mozilla Firefox浏览器使用。Trident:微软开发,被IE4~IE11浏览器使用,但是Edge浏览器已转向Bilnk。Webkit:苹果基于KHTML开发,开源的,用于Safari,Google Chrome之前也在使用。Blink:是Webkit的一个分支,Google开发,目前应用于Google Chrome、Edge、Opera等。- 其它
四、浏览器渲染过程
- 解析HTML标签,构建DOM树 。
- 解析CSS,构建CSSOM树。
- 把DOM和CSSOM组合成渲染树(render tree)。
- 在渲染树的基础上进行布局,计算每个节点的几何结构。
- 把每个节点绘制到屏幕上(painting)。
在执行过程中,如果HTML解析遇到了JavaScript标签,则停止解析HTML去加载和执行JavaScript代码。此时,JavaScript代码就由JavaScript引擎来执行。
五、JavaScript引擎
1.认识JavaScript引擎
1.1.JavaScript引擎的作用
高级的编程语言需要转成最终的机器指令来执行。- 编写的
JavaScript交给浏览器或者Node执行,最后都是需要被CPU执行。 CPU只认识自己的指令集,即机器语言,才能被CPU所执行。- 所以需要
JavaScript引擎将JavaScript代码翻译成CPU指令来执行。
1.2.常见的JavaScript引擎
SpiderMonkey:第一款JavaScript引擎。Chakra:微软开发,用于IE浏览器。JavaScriptCore:Apple公司开发,Webkit中的JavaScript引擎。V8:Google公司开发。- 其它
2.浏览器内核VSJavaScript引擎
以Webkit为例,Webkit由两部分组成:
WebCore:负责HTML解析、布局、渲染等相关工作。JavaScriptCore:解析、执行JavaScript代码。
3.V8引擎
定义:
C++编写的开源高性能JavaScript和WebAssembly引擎,用于Chrome和Node.js等。- 实现
ECMAScript和WebAssembly。 - 可以独立运行,也可以嵌入到任何
C++应用程序中。
原理(重点):
Parse解析阶段:Parse模块将JavaScript代码转成AST(抽象语法树),因为解释器不直接认识JavaScript代码。- 如果函数没有被调用,是不会被转成AST的。
- Parse的V8官方文档:v8.dev/blog/scanne…
Ignition解释阶段:Ignition是一个解释器,将AST转换成ByteCode(字节码)。- 同时会收集
TurboFan优化需要的信息,如函数参数的类型信息。 - 如果函数值调用一次,
Ignition会解释执行ByteCode。 - Ignition的V8官方文档:v8.dev/blog/igniti…
- 同时会收集
TurboFan编译阶段:TurboFan是一个编译器,将字节码编译为CPU可以直接执行的机器码。- 如果函数被多次调用,就会标记为
热点函数,就会经过TurboFan转换成优化的机器码,提高代码的执行性能。 - 但是,
机器码实际上也会被还原为ByteCode,因为如果后续执行函数的过程中,类型发生了变化(如sum函数原来执行的是number类型,后来执行变成了string类型),之前优化的机器码并不能正确的处理运算,就会逆向转换成字节码。 - TurboFan的V8官方文档:v8.dev/blog/turbof…
- 如果函数被多次调用,就会标记为
- 执行阶段:
字节码转变为计算机能看懂的二进制文件进行执行。字节码可以跨平台。
性能优化:
1. 保证函数传入的参数类型一致。---使用TS
细节:
Parse过程:
Blink将源码交给V8引擎,Stream获取源码并进行编码转换。Scanner(扫描器,或者叫词法分析器(lexical analyzer))会进行词法分析(lexical analysis),词法分析会将代码转换成tokens(tokenization缩写,记号化)。tokens被转换成AST树,经过Parse(解析)和PreParse(预解析)。
Parser(语法分析器)就是直接将tokens转成AST树架构;PreParser为预解析。为什么需要预解析?- 因为不是所有的
JavaScript代码在一开始就会被执行。如果对所有的JavaScript代码进行解析,会影响网页的运行效率。 - 所以V8引擎实现了
Lazy Parsing(延迟解析)的方案,作用是将不必要的函数进行预解析,就是只解析暂时需要的内容,对于函数的全量解析是在函数被调用时才会进行。 - 比如:在一个函数outer内部定义了另一个函数inner,那么inner函数就会进行预解析,在调用inner函数的时候再解析inner函数。
- 因为不是所有的
- 生成
AST树后,会被Ignition转成字节码(bytecode),之后的过程就是代码的执行过程。