ES-module工作原理

本文参考 https://hacks.mozilla.org/201…,建议大家读原文。

ES6发布了官方的,标准化的Module特性,这一特性花了整整10年的时间。但是,在这之前,大家也都有在module化地编写JS代码。比如在server端的NodeJS,它是对CommonJS的一个实现;Require.js则是可以在浏览器使用,它是对AMD的一个实现。

ES6官方化了Module,那么在浏览器端我们不再需要在引入额外的文件来实现模块化的编程(当然浏览器的支持与否,这里暂不讨论)。ES Module的使用也很简单,相关语法也很少,无非就是一个import和export。但是,对于ES module到底是如何工作的,它又和之前的CommonJS和AMD有什么差别呢?这是接下来将要讨论的内容。

一:没有模块化的编程存在什么问题?

编写JS代码,主要是对于对变量的操作:给变量赋值,变量之间进行各种运算。正因为你的大部分代码都是对变量的操作,关于如何组织你的变量对于如何写好代码和维护就显得至关重要了。

当只有少量的变量需要考虑的时候,JavaScript提供了“scope(作用域)”来帮助你。因为在JavaScript里面,一个function不能访问定义在别的function里面的变量。

但是,这样同时也带来一个问题,假如functionA想要使用functionB的变量怎么办呢?一个通用的办法就是把functionB的变量放到functionA的上一层作用域。典型的是以前在使用jQuery的时候,如果要使用jQuery里面的方法,先要保证jQuery在全局作用域。
但是这样做的问题也很多:

1: 所有的script标签必须保证正确的顺序,这使得代码的维护变得异常艰难。
2: 全局作用域被污染。

二:模块化编程如何解决上面提到的问题?

模块,把相关的变量和function组织到一起,形成一个所谓的module scope(模块作用域)。在这个作用域里面的变量和function之间彼此是可见的。

与function不同的是,一个模块可以决定自己内部的哪些变量,类,或者function可以被其他模块可见,这个决定我们叫做“export(导出)”。而其他的模块也就可以选择性地使用这个模块导出的内容,我们通过“import(导入)”来实现。

一旦有了导入和导出,我们就可以把我们的程序按照指责划分为一个个模块,大的模块可以继续划分为更小的模块,最终这些模块组合到一起,搭建起了我们整个程序,就像乐高一样。

三:ES Module的工作原理之Module Instances

当你在模块化编程的时候,你就创建了一棵依赖树。不同依赖之间的链接来源于你使用的的每一条”import”语句。

就是通过这些”import”语句,浏览器和Node才知道它们到底要加载哪些代码。你给浏览器或者Node一个依赖树的入口文件,从这个入口文件开始,浏览器或者Node就沿着每一条”import”语句找到后面的代码。

但是,浏览器却使用不了这些文件。所有的这些文件都必须要转变为一系列被叫做“Module Records(模块记录)的数据解构,这样才能被浏览器识别这些文件到底在干什么。

在这之后,module record需要被转化为“module instance(模快实例)”。一个module instance包含2种东西:code和state。

code就是一系列的操作指令,就像菜单一样。但是,光有菜单,并不能作出菜,你还需要原材料。而state就是原材料。State就是变量在每一个特地时间点的值。当然,这些变量只是内存里面一个个保存着值的小盒子的小名而已。

而我们真正需要的就是每一个模块都有一个module instance。模块的加载就是从这个入口文件开始,最后得到包含所有module instance的完整图像。

对于,ES Module来说,这需要经历三个步骤:
1: Construction(构造)找到,下载所有的文件并且解析为module records。
2: Instantiation(实例化)
3: Evaluation(求值)

四:Module Instances的产生步骤
五:Module Instances的产生步骤之Construction
step1: Finding the file and fetching it
step1: Parsing
六:Module Instances的产生步骤之Instantiation
七:Module Instances的产生步骤之Evaluation

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理