Skip to content

2模块机制

1、CommonJS规范

这一章中主要讲了

CommonJS规范是如何产生的,后端没有规范

以及CommonJS规范中的模块规范 require、exprots、module.exports

  • 1、出现
    • CommonJS规范提出是旨在解决JavaScript在非浏览器环境中的模块化问题。
    • 先有CommonJS规范,node采用了CommonJS规范
  • 2、模块规范
    • 引用
      js
      var math = require('math');
    • 导出
      • module.exports
      js
        // ok
        exports.add = function () {
          var sum = 0,
            i = 0,
            args = arguments,
            l = args.length;
          while (i < l) {
            sum += args[i++];
          }
          return sum;
        };
        // 报错
        // exports只是module.exports的一个引用
        // exports重新赋值时,改变了他的引用
        // exports将不再指向module.exports,而是指向一个新的对象
        exports = function(){
          console.log(1)
        }
      • exports
        js
         //ok
          module.exports = {
            add:function () {}
          }
          // ok
          module.exports = function (){
            console.log(1)
          }
    • 标识
      • 模块标识其实就是传递给require()方法的参数
      • 将类聚的方法和变量等限定在私有的作用域中,同时支持引入和导出功能以顺畅地连接上下游依赖
      • 导出和引入机制使得用户完全不必考虑变量污染
      • 下个章节有详细讨论

2、node的模块实现

这一章中主要讲了

比较细致的阐述:node如何加载模块

  • 加载不同的模块:核心模块、文件模块,都进行缓存
  • 文件模块
    • 路径形式的文件模块:模块路径(多层级的node_modules)、文件定位(目录、扩展名、包)如何解析,不同情况的处理
    • 自定义模块,查找最慢
  • 编译不同模块:(缓存Module._cache对象上)
    • .js模块(头尾包装,包装在了一个方法内部,隔离作用域,全局变量从形参中获取)、
    • .node模块(不需要编译、process.dlopen()加载执行)、
    • .json模块(require加载)

3、核心模块

本章主要介绍了

核心模块组成,以及两部分如何加载、编译

核心模块引入流程(从上到下),以及编写核心组件

  • 核心模块分两部分

    • javascript编写的(Node项目lib目录),
      • 先转存为c/c++代码,生成node_natives.h头文件
      • 编译,编译成功(缓存到NativeModule._cache对象上)
      • process.binding('natives')取出放置在NativeModule._source
    • c/c++编写的(Node项目src目录)(内建模块),
      • NODE_MODULE宏将模块定义到node命名空间中,
      • node_extensions.h 将内建模块统一放进了一个叫node_module_list的数组中
      • get_builtin_module()从node_module_list数组中取出
      • 如何导出
        • Node在启动时,全局变量process,提供Binding()方法来协助加载内建模块
        • Binding方法:
          • 先创建一个exports空对象,调用get_builtin_module()方法取出内建模块对象,
          • 通过执行register_func()填充exports对象,
          • 最后将exports对象按模块名缓存,并返回给调用方完成导出。
  • 核心模块引入流程

    • require("os") -> NativeModule.require("os") -> process.binding("os") -> get_builtin_module("node_os") -> NODE_MODULE(node_os,reg_func)
  • 编写核心模块

    • js文件
    • 编写头文件和编写C/C++文件
    • 还需要更改src/node_extensions.h,在NODE_EXT_LIST_END前添加NODE_EXT_LIST_ITEM(node_hello)
    • 让编写的两份代码编译进执行文件,同时需要更改Node的项目生成文件node.gyp

4、c/c++扩展模块

本章主讲:

1、c/c++扩展模块的编写、编译、加载等

2、目前只需了解一下整个的过程,等学习c++以后,可以再重新编写

  • 1、c/c++扩展模块的优势,比js更有性能的优势(位运算)
  • 2、原生模块编译:
    • 在不同的平台(linux\windows),
    • 也是用了node-gyp
    • 底层的编译工具链,用不同的编译软件(g++/gcc、vc++),
    • 生成不同的文件(.so、.dll),但都是.node
  • 3、c/c++扩展模块的
    • 编写:.js、./hello/hello.cc(与内建模块有区别,没有node_module_list链表)
    • 编译:GYP编译(跨平台)、node-gyp configure、node-gyp build、./build/Release/hello.node
    • 加载:require、process.dlopen()、uv_dlopen()/uv_dlsym()(libuv库进行封装的)
    • 优点:加载之后不需要编译、增强拓展

5、模块调用栈

本章主讲:

模块之间的调用关系

npm包

  • 模块之间的调用关系
    • 包结构
    • 包描述文件package.json
      • maintainers 维护者
      • contributors 贡献者
      • bugs bug反馈
      • repositories 源代码
      • homepage 当前包的网站地址
      • bin 命令行工具
  • npm
    • npm install -g name
      • 全局模式这个称谓其实并不精确,存在诸多误导。
      • 实际上,-g是将一个包安装为全局可用的可执行命令
    • npm adduser 注册
    • npm owner 管理包的权限
      • npm owner ls <package name>
      • npm owner add <user> <package name>
      • npm owner rm <user> <package name>
    • npm ls分析包
  • 企业搭建自己的NPM仓库
  • 优良优秀的包
    • 具备良好的测试。
    • 具备良好的文档(README、 API) 。
    • 具备良好的测试覆盖率。
    • 具备良好的编码规范。 -更多条件。

6、前后端共用模块

模块向前端的发展

  • 模块规范为了适用前端的场景,出现了异步模块定义
  • amd define(id?, dependencies?, factory)
  • cmd 与amd区别在于定义模块和依赖引入的部分
  • 当前这些都已经走进了历史,现在esmodule的天下了