这里有新鲜出炉的 Node.js 主要方法使用说明,程序狗速度看过来!
Node.js 是一个基于 Chrome JavaScript 运行时建立的一个平台, 用来方便地搭建快速的 易于扩展的网络应用 · Node.js 借助事件驱动, 非阻塞 I/O 模型变得轻量和高效, 非常适合 运行在分布式设备 的 数据密集型 的实时应用
这篇文章主要介绍了 Node.js 中的模块机制学习笔记, 本文讲解了 CommonJS 模块规范、Node 模块实现过程、模块调用栈、包与 NPM 等内容, 需要的朋友可以参考下
Javascript 自诞生以来,曾经没有人拿它当做一门编程语言。在 web 1.0 时代,这种脚本语言主要被用来做表单验证和网页特效。直到 Web 2.0 时代,前端工程师利用它大大提升了网页上的用户体验,JS 才被广泛重视起来。在 JS 逐渐流行的过程中,它大致经历了工具类库、组件库、前端框架、前端应用的变迁。Javascript 先天就缺乏一项功能:模块,而 CommonJS 规范的出现则弥补了这一缺陷。本文将介绍 CommonJS 规范及 Node 的模块机制。
在其他高级语言中,Java 有类文件,Python 有 import 机制,PHP 有 include 和 require。而 JS 通过 <script> 标签引入代码的方式显得杂乱无章。过去人们不得不用命名空间等方式来人为地约束代码,直到 CommonJS 规范的出现,前后端的 Javascript 才得以实现大一统。Node 借鉴了 CommonJS 的 Modules 规范实现了一套非常易用的模块系统。
1. CommonJS 模块规范
CommonJS 的模块规范分为 3 个部分:
1). 模块引用:通过 require() 方法并传入一个模块标识来引入一个模块的 API 到当前上下文中,如 var math = require('math'); 2). 模块定义:通过 exports 对象来导出当前模块的方法或变量。模块中还存在一个 module 对象,exports 实际上是 module 的属性。在 Node 中,一个文件就是一个模块,模块内的 "全局变量" 对外都不可见,只有挂载在 exports 上的属性才是公开的,如 exports.add = function() {}; exports.PI = 3.1415926; 3). 模块标识:实际上就是传递给 require() 的参数,如上述的'math',它必须是符合 camel 命名法的字符串,或者是以"."".." 开头的相对路径或绝对路径,它可以没有文件名后缀 ".js"
2. Node 模块实现过程
在 Node 中,模块分为两类:一类是 Node 本身提供的核心模块,另一类是用户自己编写的文件模块。核心模块有一部分在 Node 源代码的编译过程中,编译成了二进制文件,在 Node 启动时核心模块就被直接加载进内存中,所以它的加载速度是最快的。文件模块则是在运行时动态加载,需要经历三个步骤:路径分析,文件定位,编译执行。注意,Node 对引入过的模块都会进行缓存,以减少二次引入时的开销,并对相同模块的二次加载都采用最优先从缓存加载的策略。
2.1 路径分析
路径分析主要分析上述提到的模块标识符,主要分为以下几类:
1)、核心模块,如 http、fs、path 等 2)、. 或.. 开始的相对路径文件模块 3)、以 / 开始的绝对路径文件模块 4)、自定义文件模块,可能是一个文件或包的形式。Node 会根据模块路径数组 module.paths 来逐个尝试查找目标文件,通常是沿着当前目录逐级向上直到根目录查找名为 node_modules 的目录,所以这是查找最费时的一种方式。
2.2 文件定位
在路径分析的基础上,文件定位需要注意如下细节:
1)、文件扩展名分析:由于 CommonJS 规范允许模块标识不填写扩展名,Node 会按. js、.json、.node 的次序不足扩展名,依次尝试 2)、目录分析和包:若通过上述文件扩展名分析后没有查找到对应文件,却得到一个目录,Node 会把目录当做一个包来处理
2.3 编译执行
定位到具体文件后,Node 会新建一个模块对象,根据路径载入并编译。对于不同的扩展名,载入方法有所不同:
1)、.js 文件:通过 fs 模块同步读取文件并编译执行 2)、.node 文件:这是用 C/C++ 编写的扩展文件,通过 dlopen() 方法加载 3)、.json 文件:通过 fs 模块同步读取文件,用 JSON.parse() 解析返回结果 4)、其余扩展名文件:都被当做. js 文件载入
我们知道每个模块文件中默认都存在着 require、exports、module 这 3 个变量,甚至在 Node 的 API 文档中,我们知道每个模块还有 filename、dirname 这 2 个变量的存在,它们是从何而来的呢?Node 的模块又是怎么做到声明的 "全局变量" 实际上是不会污染到其他模块的?事实上,Node 在编译 JS 模块过程中会对文件内容进行头尾包装。下面是一个 JS 文件经过头尾包装的例子:
- (function(exports, require, module, __filename, __dirname) {
- /* 中间是JS文件的实际内容 */
- var math = require('math');
- exports.area = function(radius) {
- return Math.PI * radius * radius;
- };
- /* JS文件的实际内容结束 */
- });
这样每个模块文件之间都进行了作用域隔离,同时 require、exports、module 等变量也被注入到了模块的上下文当中。这就是 Node 对 CommonJS 模块规范的实现。关于 C/C++ 模块及 Node 核心模块的编译过程较为复杂,不再赘述。
3. 模块调用栈
有必要明确一下 Node 中各种模块的调用关系,如下图所示:
C/C++ 内建模块是最底层的模块,属于核心模块,主要提供 API 给 Javascript 核心模块和第三方 Javascript 文件模块调用,实际中几乎不会接触到此类模块。Javascript 核心模块主要职责有两种:一种是作为 C/C++ 内建模块的封装层和桥接层供文件模块调用,另一种是纯粹的功能模块,不需要跟底层打交道。文件模块通常由第三方编写,包括普通 Javascript 模块和 C/C++ 扩展模块。
4. 包与 NPM
4.1 包结构
包本质上是一个存档文件(一般为. zip 或. tar.gz),安装后解压还原为目录。CommonJS 的包规范由包结构和包描述文件两部分组成。一个完全符合 CommonJS 规范的包结构应包含以下文件:
1).package.json:包描述文件 2).bin:存放可执行二进制文件的目录 3).lib:存放 Javascript 代码的目录 4).doc:存放文档的目录 5).test:存放单元测试用例的目录
4.2 包描述文件
包描述文件是一个 JSON 文件——package.json,位于包的根目录下,是包的重要组成部分,用于描述包的概况信息。后面要提到的 NPM 的所有行为都与这个文件的字段息息相关。下面将以知名 Web 框架 express 项目的 package.json 文件为例说明一些常用字段的含义。
1).name:包名 2).description:包简介 3).version:版本号,需遵照 "语义化的版本控制",参照 http://semver.org/ 4).dependencies:使用当前包所需要依赖的包列表。这个属性十分重要,NPM 会通过这个属性自动加载依赖的包 5).repositories:托管源代码的位置列表
其余字段的用法可以参照 NPM package.json 说明
4.3 NPM 常用功能
NPM(node package manager),通常称为 node 包管理器。它的主要功能就是管理 node 包,包括:安装、卸载、更新、查看、搜索、发布等。
4.3.1 NPM 包安装
Node 包的安装分两种:本地安装、全局安装。两者的区别如下:
1). 本地安装 npm install
4.3.2 NPM 包管理
下面以 grunt-cli(grunt 命令行工具)为例,列出常用的包管理命令:
1).npm install:安装 package.json 文件的 dependencies 和 devDependencies 字段声明的所有包
2).npm install grunt-cli@0.1.9:安装特定版本的 grunt-cli
3).npm install grunt-contrib-copy --save:安装 grunt-contrib-copy,同时保存该依赖到 package.json 文件
4).npm uninstall grunt-cli:卸载包
5).npm list:查看安装了哪些包
6).npm publish
来源: http://www.phperz.com/article/17/0518/274406.html