当我们在浏览器上输入网址去访问一个页面时:
- 首先会将域名通过DNS解析成ip地址(服务器地址)
- 服务器会为我们返回index.html
- 浏览器去解析index.html,遇到link标签时去下载css资源,遇到script标签时去下载js文件
- 至此,资源已下载完毕,那么谁来解析HTML并将内容呈现出来呢?——那就是浏览器内核了
- 而JavaScript是一门高级的编程语言,但计算机不认识高级语言,高级语言需要被编译为机器指令来被CPU执行,这又是谁来解析、执行JS代码的呢?——那就是JS引擎了
一、浏览器内核
浏览器内核指的是浏览器排版引擎,也称浏览器引擎、页面渲染引擎。
不同浏览器内核不同:
1-1、各浏览器内核
浏览器 | 内核 | 备注 |
---|---|---|
IE | Trident | IE、360极速浏览器、百度浏览器、猎豹安全浏览器内核 |
FireFox | Gecko | 火狐浏览器内核 |
Safari | Webkit | 苹果浏览器内核 |
Chrome/Opera | Blink | Blink其实是Webkit的一个分支 |
1-2、浏览器渲染过程
- 首先内核通过HTML Parser将HTML转化为DOM Tree
- 内核再通过CSS Parser对CSS进行解析为 Style Rules
- 然后将DOM Tree 与 Style Rules附加在一起生成渲染树Render Tree(DOM Tree + Style Rules -> Render Tree)
- 再对RenderTree进行布局生成最后的RenderTree
- 最后将RenderTree进行绘制,展示出来
二、JS引擎
2-1、常见的JS引擎
JS引擎 | 说明 |
---|---|
SpiderMonkey | 第一款JavaScript引擎,由Brendan Eich开发(也就是JavaScript作者) |
Chakra | 微软开发,应用于IE浏览器 |
JavaScriptCore | 苹果公司开发,Webkit中的JS引擎 |
V8 | Google开发 |
2-2、V8引擎架构
2-3、V8引擎原理
V8使用C++编写的Google开源高性能JavaScript和WebAssembly引擎,它用于Chrome和Node.js等
- 首先,V8对JS源代码进行词法分析、语法分析生成AST抽象语法树
- 词法分析:生成tokens数组,tokens数组由多个对象组成,对象中包含了type与value等(如:{ type: 'keywords', value: 'const'})
- 语法分析:对其中的每个对象进行分析,根据其type分析成具体的语法,生成AST抽象语法树
- 拿到抽象语法树后,由ignition库(V8中的库)将抽象语法树转成字节码(字节码可跨平台)
- 之所以不直接转为机器指令是因为JS运行环境是无法确定的(比如有可能运行在Mac上的Chrome,也可能运行在Windows上的Chrome),不同环境的CPU不同,对应的机器码也不同
- V8再将字节码转成对应平台的机器指令
- Ignition库会收集函数执行频率等信息,如果执行频率过多,那么就会由TurboFan库直接变为机器码,就不用先转为字节码,再变为机器指令了(优化)
- 一旦发现下次执行机器指令时操作不同了,那么会进行反向优化,将优化的机器码转成字节码
2-4、V8执行细节
JavaScript源码被解析的过程:
- Bink将源码交给V8引擎,Stream获取到源码并且进行编码转换
- Scanner会进行词法分析,词法分析会将代码转换成tokens数组
- 然后tokens会被转化为AST树,其间会经过Parser(解析) 与PreParser(预解析)
- Parser会直接将tokens转为AST
- PreParser预解析,为什么要进行预解析呢?
- 是因为并不是所有的JS代码在一开始就是会被执行的(函数在被调用时才会执行),对所有的JS代码解析会影响网页的运行效率
- 于是V8引擎实现了延迟解决方案:将不必要的函数进行预解析,只解析暂时需要的内容
- 而对于函数的全量解析是在函数被调用时进行的
- 生成AST树后,会被Ignition转成字节码,之后就是执行代码啦(代码执行过程文章详见下一篇~)