[TOC]

模块模式;依赖图;异步模块加载;单例;动态依赖;静态分析;
默认导出;命名导出;模块转移导出;

疑问:

  • 动态依赖和异步加载模块的区别?
    • 动态依赖是指在程序结构中加载模块,而异步加载模块在构建依赖图时进行,是原属于AMD的更优越的模块加载方案,本身就是2个概念。
  • 单例的意思是?
    • 看书中的描述,应该是指:无论模块请求多少次,只加载一次,只存在一个实例。
  • 模块加载到底是编译时发生还是代码执行时发生?【todo】

    • 直觉上是编译时,但是不确定。“只有整个依赖图都加载完成,才可以执行入口模块”,根据这条记录,在依赖图加载完毕前,连入口文件都不会走,怎么可能在代码执行时才完成模块加载呢?

      书摘&心得:

      1 模块模式

  • 模块系统本质上是键/值实体,其中每个模块都有个可用于引用它的标识符。

    • 每个模块都会与某个唯一的标识符关联,该标识符可用于检索模块。
  • 模块系统的核心是管理依赖(外部模块)。
    • 模块系统检视这些依赖,进而保证这些外部模块能够被加载并在本地模块运行时初始化所有依赖。
  • 相互依赖的模块必须指定一个模块作为入口(entry point),这也是代码执行的起点。
    • 只有整个依赖图都加载完成,才可以执行入口模块。
  • 异步加载
    • 传统模块加载是“阻塞的”,这意味着前置操作必须完成才能执行后续操作。
    • 5个模块互相依赖,如何正确管理加载顺序十分棘手
      • image.png
      • 因为JavaScript可以异步执行,所以如果能按需加载就好了
    • 异步依赖伪代码
      • image.png
      • 这样依赖顺序一目了然,无需多费心
  • 动态依赖
    • 动态依赖必须在模块执行前加载完毕
    • image.png
    • 可以支持更复杂的依赖关系,但代价是增加了对模块进行静态分析的难度
  • 静态分析
    • 模块中包含的发送到浏览器的JavaScript代码经常会被静态分析。
    • 分析工具会检查代码结构并在不实际执行代码的情况下推断其行为。
    • 对静态分析友好的模块系统可以让模块打包系统更容易将代码处理为较少的文件。
    • 更复杂的模块行为,例如动态依赖,会导致静态分析更困难。
  • 模块加载顺序可能会出人意料

    • 存在循环依赖
    • 要构建一个没有循环依赖的JavaScript应用程序几乎是不可能的

      2 CommonJS

  • Node.js使用了轻微修改版本的CommonJS

  • 以服务器端为目标环境,能够一次性把所有模块都加载到内存
    • 因此CommonJS模块加载是模块系统执行的同步操作
  • 使用require()指定依赖;使用exports对象定义自己的公共API
    • image.png
  • 无论一个模块在require()中被引用多少次,模块永远是单例(无论请求多少次,moduleA只会被加载一次)
    • image.png
    • 第一次加载后会被缓存,后续加载会取得缓存的模块
  • 在CommonJS中,模块加载是模块系统执行的同步操作。因此require()可以嵌入在代码

    • import不可以不是么?必须写在顶部(这里不讨论动态导入import()),因为ES6模块是异步加载的。

      3 即将没落的模块加载器

  • 异步定义模块AMD

    • 工作原理
      • 让模块声明自己的依赖
      • 运行在浏览器中的模块系统会按需获取依赖
      • 在依赖加载完成后立即执行依赖它们的模块。
    • 核心是用函数define包装模块定义。这样可以防止声明全局变量
      • image.png
  • 通用模块定义UMD
    • UMD可用于创建这CommonJS和AMD都可以使用的模块代码。
  • 模块加载器终将没落

    • CommonJS与AMD之间的冲突正是我们现在享用的ECMAScript 6模块规范诞生的温床。
    • CommonJS到底是Node.js的模块加载器,个人感觉不至于没落,AMD和UMD倒是不常见。

      4 ES6模块

  • ES6模块系统是集AMD和CommonJS之大成者。

  • 带有type=”module”属性的