ES modules: A cartoon deep-dive

简介: ES modules: A cartoon deep-dive

原文链接

ES模块为JavaScript带来了官方的、标准化的模块系统。然而,它花了一段时间才走到这一步——将近10年的标准化工作。

但等待即将结束。随着火狐60在5月的发布(目前处于beta),所有主流浏览器都将支持ES模块,Node模块工作组目前正在努力将ES模块支持添加到Node.js中。WebAssembly的ES模块集成也在进行中。

许多JavaScript开发人员都知道ES模块一直备受争议。但很少有人真正了解ES模块是如何工作的。

让我们来看看ES模块解决了什么问题,以及它们与其他模块系统中的模块有什么不同。

What problem do modules solve?

仔细想想,用JavaScript编码就是管理变量。它就是给变量赋值,或者给变量加数字,或者把两个变量组合在一起,然后把它们放到另一个变量中。

image.png

因为你的很多代码都是关于改变变量的,你如何组织这些变量将会对你的编码有很大的影响,以及你如何维护这些代码。

一次只考虑几个变量会使事情更容易。JavaScript有一种方法可以帮助您做到这一点,称为作用域。由于JavaScript中作用域的工作方式,函数不能访问在其他函数中定义的变量。

image.png

这是很好的。这意味着当你研究一个函数时,你可以只考虑那个函数。你不必担心其他函数会对你的变量做什么。

不过,它也有一个缺点。这使得在不同函数之间共享变量变得困难。

如果你想在作用域之外共享你的变量该怎么办?处理这个问题的常用方法是将它放在你上面的作用域中,例如全局作用域中。

您可能还记得jQuery时代的这一点。在加载任何jQuery插件之前,必须确保jQuery处于全局作用域中。

image.png    

这是可行的,但是会产生一些烦人的问题。

首先,所有的脚本标记都需要按正确的顺序排列。然后你必须小心确保没有人打乱这个顺序。

如果你打乱了顺序,那么在运行过程中,你的应用程序会抛出一个错误。当函数在它期望的地方(在全局变量上)寻找jQuery而没有找到时,它将抛出一个错误并停止执行。

image.png

这使得维护代码非常棘手。它使删除旧代码或脚本标记变成了一场轮盘赌游戏。你不知道什么东西会坏掉。代码的这些不同部分之间的依赖关系是隐式的。任何函数都可以获取全局函数上的任何东西,因此您不知道哪些函数依赖于哪些脚本。

第二个问题是,因为这些变量位于全局作用域中,所以在全局作用域中的代码的每一部分都可以更改变量。恶意代码可以故意更改该变量,使您的代码做一些您不希望它做的事情,或者非恶意代码可以偶然地破坏您的变量。

How do modules help?

当您使用模块进行开发时,您将建立一个依赖关系图。不同依赖项之间的连接来自您使用的任何导入语句。

通过这些导入语句,浏览器或Node可以准确地知道需要加载哪些代码。您给它一个文件作为图形的入口点。从这里开始,它只跟随任何导入语句来查找其余的代码。

image.png

但是文件本身并不是浏览器可以使用的东西。它需要解析所有这些文件,将它们转换为称为模块记录的数据结构。这样,它就知道文件中发生了什么。

image.png

在此之后,需要将模块记录转换为模块实例。实例结合了两件事:代码和状态。

代码基本上是一组指令。这就像是制作某样东西的食谱。但就其本身而言,您不能使用代码来做任何事情。你需要原材料来配合这些说明使用。

状态是什么?状态给你这些原材料。状态是变量在任何时间点的实际值。当然,这些变量只是内存中保存值的方框的别名。

因此,模块实例将代码(指令列表)与状态(所有变量的值)结合起来。

image.png

我们需要的是每个模块的一个模块实例。模块加载的过程是从这个入口点文件到拥有一个完整的模块实例图。

对于ES模块,这需要三个步骤。

  1. Construction — 查找、下载并将所有文件解析为模块记录。
  2. Instantiation —在内存中找到放置所有导出值的方框(但不要用值填充它们)。然后让导出和导入都指向内存中的这些框。这就是所谓的链接。
  3. Evaluation —运行代码,用变量的实际值填充方框。

image.png

人们说ES模块是异步的。您可以认为它是异步的,因为工作被分为这三个不同的阶段——加载、实例化和评估——并且这些阶段可以分别完成。

这意味着规范引入了一种CommonJS中没有的异步。我将在后面进一步解释,但是在CJS中,一个模块及其下面的依赖项都是一次性加载、实例化和求值的,中间没有任何中断。

然而,这些步骤本身并不一定是异步的。它们可以以同步的方式完成。这取决于是什么在加载。这是因为并非所有的事情都由ES模块规范控制。实际上工作分为两部分,由不同的规范覆盖。

The ES module spec规定了如何将文件解析为模块记录,以及如何实例化和计算该模块。然而,它并没有说明如何首先获得这些文件。

它是获取文件的加载器。装载机在不同的规格中有规定。对于浏览器来说,这个规范就是HTML规范。但是根据所使用的平台,可以使用不同的加载器。

image.png

加载器还精确地控制模块的加载方式。它调用ES模块的方法——ParseModule, Module.Instantiate, and Module.Evaluate。它有点像控制JS引擎字符串的木偶师。

image.png

现在让我们更详细地了解每一步。

目录
相关文章
|
前端开发 JavaScript Java
ES11,ES12,ES13
ES11,ES12,ES13
107 1
ModuleNotFoundError: No module named ‘openai.error‘
这篇文章讨论了在使用OpenAI库时遇到的`ModuleNotFoundError: No module named ‘openai.error'`错误,并提供了两种解决方案:将OpenAI版本降级到0.28.0或修改代码以去掉对`openai.error`的引用并将异常处理放置到`openai`模块下。
ModuleNotFoundError: No module named ‘openai.error‘
|
3月前
|
人工智能 语音技术
ModuleNotFoundError: AutomaticSpeechRecognitionPipeline: No module named ‘funasr‘
这篇文章描述了在运行阿里语音AI模型的语音识别时遇到的`ModuleNotFoundError: No module named ‘funasr’`错误,并提供了通过`pip install funasr --upgrade -f https://modelscope.oss-cn-beijing.aliyuncs.com/releases/repo.html`命令重新安装funasr模块的解决方法。
ModuleNotFoundError: AutomaticSpeechRecognitionPipeline: No module named ‘funasr‘
|
2月前
|
JSON JavaScript 前端开发
浅谈ES5与ES6
浅谈ES5与ES6
35 3
|
4月前
|
机器学习/深度学习 IDE TensorFlow
【Python】已解决ModuleNotFoundError: No module named ‘tensorflow‘
【Python】已解决ModuleNotFoundError: No module named ‘tensorflow‘
82 1
|
JavaScript 前端开发 索引
ES9,ES10
ES9,ES10
70 0
|
TensorFlow 算法框架/工具 Python
成功解决ModuleNotFoundError: No module named '_pywrap_tensorflow_internal'
成功解决ModuleNotFoundError: No module named '_pywrap_tensorflow_internal'
解决ModuleNotFoundError: No module named ‘tensorflow_datasets‘
解决ModuleNotFoundError: No module named ‘tensorflow_datasets‘
316 0
解决ModuleNotFoundError: No module named ‘tensorflow_datasets‘
|
JSON JavaScript 前端开发
ES5和ES6的介绍
《前端基础》
423 0
|
决策智能
运筹优化25:ModuleNotFoundError: No module named ‘docplex‘
运筹优化25:ModuleNotFoundError: No module named ‘docplex‘
运筹优化25:ModuleNotFoundError: No module named ‘docplex‘