overview
讲解esm的运行逻辑。
esm是一种模块化解决方案。其他方案还有:commonjs(本文简写为cjs)/amd/umd。模块化是工程化的组成部分。
后端早就把工程化做的很好了。前端的代码还是一地鸡毛。使用拙劣的<script>
。es6为前端带来了模块化。
出生背景
- 已经存在一些简单的/补漏的模块化解决方案。如:iife.
- commonjs已经在node.js中正常运行。
虽然有这些补救措施,但是不足以完美解决前端模块化。还有一些问题没解决,如下: - 严格确定
<script>
引入顺序。 - 为了让其他脚本间协同工作。不得不使用全局变量。而全局变量又会被全局访问/使用/修改。无法限制。
能解决什么问题
- 把一大块功能分为若干小模块去开发,然后再组合为了一个模块,整合后对外输出。
- 每个模块只能操作本模块和本模块引入模块输出的变量/方法等。不需要全局变量。
- 控制本模块向外输出哪些东西。
- 没有引入顺序限制。不引入则无使用依赖,想使用依赖,就得引入依赖。
如何运行
分以下4个部分运行。
1. 发现/加载。
在浏览器中使用<script src="main.js" type="module">
指定使用的脚本。浏览器会根据url下载脚本。type="module"
会让浏览器把该文件当做module处理。该文件中可以使用import
。
浏览器会一层一层地根据依赖关系依次加载依赖。此过程需要较长时间。然后模块地图
2. 创建(也叫解析)
根据模块地图生成模块记录。然后模块记录代替模块地图。
模块记录包括:代码/状态。
代码是该模块的运行逻辑,
状态是该模块变量的实际值。
模块的url与模块一一对应。
后会生成一个入口对应若干模块记录。
3. 实例化
js引擎创建模块环境记录。里面保存了该模块的所有变量。在评估前不能被访问。
使用一块内存专门保存该模块的实例。该模块对外输出就是使用此内存。即使已经输出对象,再在该模块内修改值,也会作用于已经输出的对象。因为对象对应的内存没变。
4. 评估
执行实例化结果。
commonjs & es module
cjs的运行逻辑与esm的运行逻辑的不同。
若cjs中使用esm。则需要把文件扩展名设置为.mjs
。
cjs在实例化时会返回该模块的输出的对象。若已经输出对象,再在该模块内修改值,则不会影响已经输出的对象。
cjs已经做了一些兼容esm的功能。
future
esm/cjs正在统一。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。