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) }
- exportsjs
//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对象按模块名缓存,并返回给调用方完成导出。
- javascript编写的(Node项目lib目录),
核心模块引入流程
- 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 owner ls
- npm ls分析包
- npm install -g name
- 企业搭建自己的NPM仓库
- 优良优秀的包
- 具备良好的测试。
- 具备良好的文档(README、 API) 。
- 具备良好的测试覆盖率。
- 具备良好的编码规范。 -更多条件。
6、前后端共用模块
模块向前端的发展
- 模块规范为了适用前端的场景,出现了异步模块定义
- amd
define(id?, dependencies?, factory)
- cmd 与amd区别在于定义模块和依赖
引入
的部分 - 当前这些都已经走进了历史,现在esmodule的天下了