浏览器的工作原理
浏览器是如何下载js文件的呢?
首先在浏览器中输入域名,然后这个域名将转化服务器的IP地址,这个IP地址将返回一个文件,就是图中的index.html文件,这个时候浏览器开始解析这个网页,解析到link标签就下载css文件,解析到script标签就下载js文件。
浏览器的渲染过程
浏览器将html,css,js文件下载下来后就开始解析,这个时候由浏览器内核中的HtmlParse模块将HTML标签编译成DOMTree,这个时候可以利用js进行DOM操作将HTML元素插入到DOMTree中,而浏览器则是通过浏览器引擎来解析js的,我们在下面的内容将会重点将浏览器V8引擎。
DOMTtree生成以后将会开始解析css文件,通过cssParse模块将css解析为StyleRulesTree,接下来DOMTree和StyleRulesTree将会结合形成RenderTree。
RenderTree生成以后通过Layout引擎根据浏览器大小来生成新的renderTree,然后绘制出来,浏览器开始展示。由于有些html标签定位不同,这个时候浏览器大小不同,元素位置就不同,layout引擎的作用就是重新生成一个适合当前浏览器大小的renderTree。
V8引擎
JS引擎
高级的编程语言都是需要转成最终的机器指令来执行的
事实上我们编写的JavaScript无论你交给浏览器或者Node执行,最后都是需要被CPU执行的
但是CPU只认识自己的指令集,实际上是机器语言,才能被CPU所执行;
所以我们需要JavaScript引擎帮助我们将JavaScript代码翻译成CPU指令来执行
浏览器V8引擎是如何编译js的?
首先将js源代码通过parse模块编译成抽象语法树,之后通过Ignition模块将抽象语法树编译成字节码,然后V8引擎将字节码转化成汇编代码,汇编代码转化为对应平台的机器指令运行。
当一个函数多次执行时,Ignition模块将会把这个函数标记成一个hot函数,由TurboFan编译成优化的机器码,这样当下一次执行这个函数,就直接执行这串机器码。当然有一个前提,这个函数传递的参数类型必须一致。 例如:
function foo(n1,n2){
console.log(n1+n2)
}
foo(10,20)//此函数转化为机器码
foo(50,30)//直接执行机器码
foo("张三",20)//传递的参数类型不一样,则不会直接执行机器码,而是将机器码转化为字节码再执行
由于js是一门动态语言,它本身不会做类型检测,所以需要开发者本身尽量传递类型一致的参数,这样有利于性能的提升,因此Ts对性能提升也有帮助。
作用域提升
js源码到被编译成抽象语法树的过程中还会有这些细节
var name = "小红"
var age = 18
var address = "高老庄"
这串代码载被js引擎解析的时候会创建一个全局对象
var GlobalObject = {
String:"类"
Math:"类"
Window:GlobalObject,
setTimeout:"方法"
...
name:undefined,
age:undefined,
address:undefined
}
这个全局对象里不仅会有一些全局的方法和对象,还会将全局里定义的变量添加进去赋值为undefind(此时js代码还没有执行),当然还有一个window属性,这个属性指向GlobalObject这个全局对象。
接下来开始执行js代码,在执行的时候V8引擎会创建一个执行上下文栈(函数调用栈) 而全局的代码在执行时会创建一个全局执行上下文VO,此时的VO指向GO(GlobalObject) 此时此刻才真正开始执行下面这串代码
var name = "小红"
var age = 18
var address = "高老庄"
然后进去VO开始找name属性将其赋值为小红,由于此时的VO就是GO对象,所以将GO中的name属性的值改掉了。
而下面的一串代码:
var name = "小红"
console.log(age)//undefind
var age = 18
var address = "高老庄"
在age=18这行代码运行之前打印age的值,将会去VO对象中去找age属性,此时VO又指向GO,所以结果为undefind,这就是所谓的变量提升
- 非常感谢王红元老师的深入JavaScript高级语法让我学习到很多
JavaScript的知识。