文章目录

  • 1、js引擎
  • 2、语法分析
  • 3、预编译
  • 3.1 全局预编译
  • 3.2 局部预编译
  • 3.3 全局对象
  • 3.4 AO对象
  • 3.5 变量对象
  • 3.6 执行环境
  • 4、解释执行
  • 5、外部脚本的同步加载
  • 6、外部脚本的异步加载
  • 6.1 defer
  • 6.3 window.onload和domready


1、js引擎

脚本编译:由js引擎编译,即V8引擎(js解释器就是js引擎)

V8引擎的用处:chrome浏览器的引擎、Nodejs的运行时环境、electron的底层引擎

js引擎在编译和执行js代码会用到3个重要的组件:

解析器:负责将js源代码解析成抽象语法树AST(通过词法分析、语法分析形成AST)

解释器:负责将AST解释成字节码bytecode,也有直接解释执行bytecode的能力

编译器:负责编译出运行更加高效的机器代码

2、语法分析

首先JavaScript的执行过程会先扫描一下整体语法语句,如果存在逻辑错误或者语法错误,那么直接报错,程序停止执行,没有错误的话,开始从上到下解释一行执行一行。(预编译之后进行解释执行,解释一行,执行一行)

3、预编译

操作系统分配一段内存——全局预编译——执行script

全局执行环境:添加GO对象的属性

局部执行环境:函数调用时创建AO对象并添加属性

全局执行环境栈底载入栈底——局部执行环境载入栈顶

函数创建时生成作用域链,执行时初始化作用域链

3.1 全局预编译

创建GO对象(Global Object)全局对象。
找变量声明,将变量名作为GO属性名,值为undefined
查找函数声明,作为GO属性,值赋予函数体

3.2 局部预编译

创建AO对象(Activation Object)执行期上下文。
找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
将实参值和形参统一。
在函数体里面找函数声明,值赋予函数体。

3.3 全局对象

一个可以在js运行过程当中,由宿主环境提供的,随时随地访问的对象。全局对象在浏览器当中可以被成为window或者self。全局对象带来的是运行时,任意地点,任意元素都可以访问的,这样相当于提供了一个全局的总线模式(不推荐,容易造成命名冲突)。全局对象带来的,是宿主环境提供了一些公共的方法,比如alert,比如history,浏览器是通过window来做基础架构的,然后再window之上去架构自己的DOM方法和实现。

3.4 AO对象

函数执行,创建AO对象

3.5 变量对象

全局上下文中,变量对象,是全局对象自身
在函数上下文中,变量对象,是活动对象AO
创建变量对象时,会创建变量对象的作用域链(应该是初始化吧?)
环境中定义的所有变量和函数都保存在这个对象中

3.6 执行环境

(记得看)

JS的运行环境一般由宿主环境和执行期环境共同构成

宿主环境是由外壳程序(如web浏览器就是一个外壳程序)生成,执行期环境是由嵌入到外壳程序中的JS引擎(/JS解释器)生成的,在执行期环境JS可以生成内置静态对象、初始化执行环境等。

执行环境(execution context,为简单起见,有时也被称为“环境”)是JavaScript 中最为重用的一个概念。执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每个执行环境都有一个与之关联的变量对象(variable object),环境中定义的所有变量和函数都保存在这个对象中。虽然我们编写的代码无法访问这个变量,但解析器在处理数据时会在后台使用它。

全局执行环境是最外围的一个执行环境。在Web浏览器中,全局执行环境被认为是 window 对象,因此所有全局变量和函数都是作为window 对象的属性和方法创建的。某个执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁(全局执行环境直到应用程序退出——例如关闭网页或浏览器——时才会被销毁)。

局部执行环境,每个函数都有自己的执行环境。当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。ECMAScript 程序中的执行流正是由这个方便的机制控制着。

先生成全局执行环境,创建GO对象(GO对象即为变量对象),会创建变量对象的作用域链。栈的底部永远是全局环境,栈的顶部则是处于活动状态当前的执行环境(浏览器总是执行处于栈顶的上下文)

函数调用,局部执行环境被推入执行环境栈,进行局部预编译(创建AO对象,生成局部作用域链)(每次函数的调用都会创建一个执行环境压入栈中,无论是函数内部的函数、还是递归调用等。)

4、解释执行

v8将js代码转换为汇编语言,解释一行,执行一行
汇编语言是低级语言,面向CPU的语言,控制CPU,是二进制的文本语言
词法分析,语法分析,全局环境上下文,执行(代码生成,运行),函数环境上下文,执行
词法分析:把输入的字符串分解成一些对编程语言有意义的代码块、
语法分析:将词法单元转换成一颗抽象语法树(AST)
代码生成:将 AST 代码转换为可执行代码。简单来说,就是将 AST 转化为一组机器指令,用来创建一个叫做 a 的变量(包括分配内存等),并将一个值 10 存储在 a 中。

5、外部脚本的同步加载

蓝:文档渲染,紫:加载js文件,黄:执行js

同步加载缺陷:执行JS过程中停止对HTML元素的解析,保证JS执行的安全一致性,但如果JS中包含大量计算、输出document内容、修改dom、重定向等时,会导致阻塞页面的渲染。一般放在body后面。

加载:下载网络资源

解析:一行一行执行代码

渲染:浏览器渲染

javascript 编译引擎 js编译器_异步加载

6、外部脚本的异步加载

6.1 defer

使用:script的属性,只支持外部脚本的加载

缺陷:这种加载方式执行完之前会阻塞onload事件的触发,而现在很多页面的代码都在onload时还执行额外的渲染工作,所以还是会阻塞部分页面的初始化处理。

javascript 编译引擎 js编译器_defer和async_02

参考博客:

13.6.2 async

javascript 编译引擎 js编译器_异步加载_03


javascript 编译引擎 js编译器_defer和async_04


6.3 window.onload和domready

window.onload等到页面内包括图片的所有元素和资源加载完毕后才能执行时间点2;
$(document).ready()是DOM加载完毕后就执行,不必等到整个网页资源加载完毕,1;
当页面上的所有HTML都转换为节点,就称为DOMReady
所以,使用document.ready()方法的执行速度比window.onload的方法要快。