shizhihuaxu / study-notes

学习笔记,见 issues
0 stars 0 forks source link

模块化方案 #30

Open shizhihuaxu opened 3 years ago

shizhihuaxu commented 3 years ago

CommonJS(Nodejs,同步)

  1. CJS 使用不同的算法是因为它从文件系统加载文件,这耗费的时间远远小于从网络上下载。因此 Node 在加载文件的时候可以阻塞主线程,而不造成太大影响。而且既然文件已经加载完成了,那么它就可以直接进行实例化和运行。所以在 CJS 中实例化和运行并不是两个相互独立的阶段,而是连续不间断的。

  2. 在 CJS 中,整个导出对象在导出时都是值拷贝。即,所有的导出值都是拷贝值,而不是引用。所以,如果导出模块内导出的值改变了,导入模块中导入的值也不会改变。

  3. AMD/CMD 是 CommonJS在浏览器端的解决方案。

    CommonJS是同步加载(代码在本地,加载时间基本等于硬盘读取时间)。

    AMD/CMD是异步加载(浏览器必须这么做,代码在服务端)

    UMD 是 AMD 与 CommonJS 的结合,跨平台的解决方案;UMD先判断是否支持Node.js的模块(exports)是否存在,存在则使用Node.js模块模式。再判断是否支持AMD(define是否存在),存在则使用AMD方式加载模块。

ES Module(esm,ECMAScript Nodule,异步)

  1. js 的模块化标准

  2. 解决什么问题

    • 解决变量管理,变量作用域与访问,变量共享的问题,提供一种更好的方式管理变量和函数,将相关的变量和函数放在一个模块中,模块作用域,共享数据。

    • 对外暴露的过程为导出,导入此模块的模块就可以显示的声明依赖此模块的数据,是一种明确的依赖关系

    • 从入口文件,根据依赖关系加载各个依赖文件,但是不能直接使用,而是进行解析,将模块关系记录下来,解析后将代码和状态(变量的实际值)结合起来,形成模块实例。模块加载会从入口文件开始,最终生成完整的模块实例关系图。

  3. 同其它模块化系统有什么区别

  4. ESM 生成模块实例的过程:

    • 加载。从入口开始找出所有文件,下载,把所有文件解析成模块记录
    • 实例化。为模块分配内存空间,然后依据导入导出语句把模块指向对应的内存地址。
    • 运行。运行代码,将内存空间填充为真实值
  5. 为什么说 esm 是异步的?

    • 因为它把整个过程分为了三个不同的阶段:加载、实例化和运行,并且这三个阶段是可以独立进行的。(顺序固定。但不必一个完成立即执行下一步,例如使用 webpack 构建项目,打包后未运行,待部署后再真正执行)
  6. 模块定位符 (import from 'specifier', export)

  7. 动态 import() ,实际上把加载的模块当成了入口文件,会生成一个新的模块依赖关系树,与非 动态import的依赖关系树共有的模块会共享同一个模块实例,因为加载器会缓存模块实例,并且再全局范围内一个模块只会存在一个模块实例。

  8. 加载器会缓存模块,一个模块文件只会被下载一次,即使有多个模块依赖它。使用模块映射,每个全局作用域有一个独立的模块映射,加载文件后会将 url 记录在模块映射中,如果有其它模块也依赖于这个模块,会自动跳过下载。

  9. 解析目标(解析方式),对同一个文件不同的解析目标会生成不同的结果

  10. ESM 则使用称为实时绑定(Live Binding)的方式。导出和导入的模块都指向相同的内存地址(即值引用)。所以,当导出模块内导出的值改变后,导入模块中的值也实时改变了。

  11. 模块导出的值在任何时候都可以能发生改变,但是导入模块却不能改变它所导入的值,因为它是只读的。

shizhihuaxu commented 3 years ago
  1. import() 动态加载模块,运行时执行,返回一个 promise 对象;
  2. import()函数可以用在任何地方,不仅仅是模块,非模块的脚本也可以使用;
  3. 与所加载的模块没有静态连接关系;