1.什么是模块?

  指在程序设计中,为完成某一功能所需的一段程序或子程序;或指能由编译程序、装配程序等处理的独立程序单位;或指大型软件系统的一部分。 ----《百度百科》

2.JavaScript缺乏模块机制。

  -> 薄弱的JavaScript规范:

    (1)没有模块系统;

    (2)标准库较少(对于I/O流,文件系统等常见需求没有标准API);

    (3)没有标准接口(没有Web服务器或数据库之类的标准统一接口);

    (4)缺乏包管理系统(使JavaScript应用中基本没有自动加载和安装依赖的能力);

  -> CommonJS规范(大部分为草案):

    (1)内容:模块    二进制    Buffer    字符集编码    I/O流    进程环境    文件系统    套接字  单元测试  Web服务器网关接口  包管理  ...

    (2)目的:使用CommonJS API写出的应用可以具备跨宿主环境执行的能力。

  -> CommonJS模块规范:

    (1)【模块引用】:



var math = require('math'); // require()方法 -> 接受模块标识,并引入一个模块的API到当前上下文。



    (2)【模块定义】:

      require() 方法 -> 导入模块 

      exports() 方法 -> 导出当前模块的方法或变量(唯一的导出口)  ----

                                       |---->  JS文件中

      module对象 -> 存在于模块中,代表模块自身,拥有exports属性 ----

    (3)【模块标识】:

      传递给require()方法的参数,

      必须符合小驼峰命名的字符串,

      或以.、..开头的相对路径或绝对路径,

      可以没有.js后缀。

   ->模块规范的意义

“使用户可以在完全不必考虑变量污染的前提下,建立上下游的依赖关系。”

3.Node的模块实现

  (1)模块引入的步骤:

    A.【路径分析】(通过模块标识符):

      -> 模块标识符的分类:

        -> 核心模块,如http、fs、path等;

        -> .或..开始的相对路径文件夹;

        -> 以/开始的绝对路径文件模块;

        -> 非路径形式的文件模块,如自定义的connect模块。

    B.【文件定位】

      -> 文件扩展名分析

      -> 目录分析和包

    C.【编译执行】

      在Node中,每个文件模块都是一个对象,其定义如下:



function Module(id, parent) {
        
    this.id = id;

    this.exports = {};

    this.parent = parent;

    if (parent && parent.children) {
        
        parent.children.push(this);
    
    }

    this.filename = null;

    this.loaded = false;

    this.children = [];

}



 

  (2)模块分类:

    A.核心模块 -- Node提供的模块 (仅需路径分析,加载速度快)

    B.文件模块 -- 用户编写的模块(三步执行,加载速度较慢)

  (3)模块的缓存加载:

    无论是核心模块还是文件模块,require()方法对相同模块的二次加载都一律采用缓存优先的方式,这是第一优先级的。

4.Node核心模块

  (1)JavaScript编写的核心模块(存放在lib目录下) -> 需转存为C/C++代码

    *与文件模块的区别:

      A. 获取源码的方式(核心模块是从内存中加载的)

      B. 缓存执行结构的位置

  (2)C/C++编写的核心模块(存放在src目录下)-> 统称为“內建模块”(buffer、crypto、evals、fs、os等模块)

    优势:

      A. 性能优于脚本语言

      B. 被编译进二进制文件,一旦Node开始执行,他们被直接加载仅内存中,无需在做标识符定位、文件定位、编译等过程,直接就可以执行

    內建模块的导出:

      内建模块 -> 核心模块 -> 文件模块

5.包与NPM

  包与NPM是将模块联系起来的一种机制。

  模块 -> 一定程度上解决了变量依赖、依赖关系等代码组织性问题

  包 -> 在模块的基础上进一步组织JavaScript代码

  (1)包规范 -- 帮助Node解决依赖包安装的问题。

    A. 包结构

      包实际上是一个存档文件,即一个目录直接打包为.zip或tar.gz格式的文件,安装后解压还原为目录。

      完全符合CommonJS规范的包目录应该包含如下这些文件。

        package.json :包描述文件 -> name(包名),description(简介),version(版本号),keywords(关键词数组),maintainers(包维护者列表)

        bin :用于存放可执行二进制文件目录

        lib :用于存放JavaScript代码的目录

        doc :用于存放文档目录

        test :用于存放单元测试用例的代码

    B. 包描述

      用于表达非代码相关的信息,它是一个JSON格式的文件 -- package.json 位于包的根目录下,是包的重要组成部分。

      NPM的所有行为斗鱼包描述文件的字段息息相关。

  (2)NPM -- 包规范的一种实践,帮助完成了第三方模块的发布、安装和依赖等。

    借助NPM,Node与第三方模块之间形成了很好的生态系统。

    借助NPM,可以帮助用户快速安装和管理依赖包。

  (3)安装包,引用包,发布包

    安装包:$npm install express -> node_modules > express

    引用包:require()

    发布包:保存js文件 -> $npm init -> $npm adduser -> npm pulish <folder>

  (4)NPM的潜在问题 -> 包质量与安全问题

6.前后端功用模块

  前后端JavaScript分别搁置在HTTP的两端,他们扮演的角色并不同。

  浏览器端的JavaScript需要经历从同一个服务器端分发到多个客户端执行 -> 瓶颈在于带宽 -> 需要网络加载代码(慢)

  服务器端的JavaScript需要经历相同的代码需要多次执行 -> 瓶颈在于CPU和内存资源 -> 直接从磁盘中加载(块)

  解决的方式 -> AMD规范 && CMD规范

  AMD规范:

    AMD规范是CommonJS模块的一个延伸。

    define(id?, dependencies?, factory);

    id : 模块id(可选)

    dependencies : 依赖(可选)

    factory : 实际的代码内容

  CMD规范:

    更接近CommonJS规范的定义。

    define(factory)

    在依赖部分,支持动态引入:

    define(function(require, exports, module) {

      // The module code goes here

    });

    require、exports和module通过形参传递给模块,在需要依赖模块时,随时调用require()引入。