返回 blog
2022年8月29日
1 分钟阅读

es6编译时加载和静态加载

ES6 入门教程 es6 入门教程中有这样一句话:

由于 ES6 模块是编译时加载,使得静态分析成为可能。有了它,就能进一步拓宽 JavaScript 的语法,比如引入宏(macro)和类型检验(type system)这些只能靠静态分析实现的功能。

如何去理解 js 的编译时加载呢

由于 js 是一门解释性语言,跟 go 不同,go是先整体编译后运行,而 js 是一边编译一边运行(js 执行引擎实现此功能) 编译时 就是还没真正运行时的代码。在运行之前,js 引擎编译的时候确定模块之间的关系,我估计跟webpack类似,有个关系图。编译好了之后立即运行,然后继续编译下一块代码,然后再运行。边编译边运行就是这样的 脚本执行有3个阶段,语法分析 脚本编译(静态分析)和实际执行。import在脚本编译阶段就生效,但是不执行。 以 V8 引擎为例,在 V8 引擎中 JavaScript 代码的运行过程主要分成三个阶段。

  1. 语法分析阶段。该阶段会对代码进行语法分析,检查是否有语法错误(SyntaxError),如果发现语法错误,会在控制台抛出异常并终止执行。
  2. 编译阶段。该阶段会进行执行上下文(Execution Context)的创建,包括创建变量对象、建立作用域链、确定 this 的指向等。每进入一个不同的运行环境时,V8 引擎都会创建一个新的执行上下文。
  3. 执行阶段。将编译阶段中创建的执行上下文压入调用栈,并成为正在运行的执行上下文,代码执行结束后,将其弹出调用栈。

JS 引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,ES6 的import有点像 Unix 系统的“符号连接”,原始值变了,import加载的值也会跟着变。因此,ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块

JavaScript引擎本质是一个程序。只不过这个程序可以将 JS 代码编译为不同 CPU对应的汇编代码,此外,还负责执行代码、分配内存以及垃圾回收等

es6之前,js 执行引擎没有静态分析的功能,es6的设计是尽量静态化,所以执行引擎新增了针对 js 代码静态分析的功能

有了静态加载后,便有了 tree-shaking

tree-shaking 是基于静态加载实现的。因为开发者可以通过一些关键字来知道代码有没有被使用到,从而做到摇树优化

有了静态加载,便有了 typescript吗?

答案是否定的,TypeScript是JavaScript的运行时,带有编译时类型检查器