Node.js入门 NPM
参考一 Node入门 七天学会NodeJS Node.js v4.2.4 手册 & 文档 Node.js 教程 node.js摸石头系列 从零开始学习node.js What is npm? Node.js v4.4.7Documentation
NodeJS
NodeJS基础
JS是脚本语言,脚本语言都需要一个解析器才能运行。对于写在HTML页面里的JS,浏览器充当了解析器的角色。而对于需要独立运行的JS,NodeJS就是一个解析器。
每一种解析器都是一个运行环境,不但允许JS定义各种数据结构,进行各种计算,还允许JS使用运行环境提供的内置对象和方法做一些事情。例如运行在浏览器中的JS的用途是操作DOM,浏览器就提供了document
之类的内置对象。而运行在NodeJS中的JS的用途是操作磁盘文件或搭建HTTP服务器,NodeJS就相应提供了fs
、http
等内置对象。
模块
编写稍大一点的程序时一般都会将代码模块化。
在NodeJS中,一般将代码合理拆分到不同的JS文件中,每一个文件就是一个模块,而文件路径就是模块名(文件名就是模块名)。
在编写每个模块时,都有require
、exports
、module
三个预先定义好的变量可供使用。
require
require
函数用于在当前模块中加载和使用别的模块,传入一个模块名,返回一个模块导出对象。
require方能看到的只有module.exports这个对象,它是看不到exports对象的,而我们在编写模块时用到的exports对象实际上只是对module.exports的引用。
exports
exports
对象是当前模块的导出对象,用于导出模块公有方法和属性。
别的模块通过require
函数使用当前模块时得到的就是当前模块的exports
对象
module
通过module
对象可以访问到当前模块的一些相关信息,但最多的用途是替换当前模块的导出对象。
例如模块导出对象默认是一个普通对象,如果想改成一个函数的话,可以使用以下方式。
module.exports = function () {
console.log('Hello World!');
};
模块初始化
一个模块中的JS代码仅在模块第一次被使用时执行一次,并在执行过程中初始化模块的导出对象。之后,缓存起来的导出对象被重复利用。
主模块
通过命令行参数传递给NodeJS以启动程序的模块被称为主模块。主模块负责调度组成整个程序的其它模块完成工作。
代码的组织和部署
有经验的C程序员在编写一个新程序时首先从make文件写起。同样的,使用NodeJS编写程序前,为了有个良好的开端,首先需要准备好代码的目录结构和部署方式,就如同修房子要先搭脚手架。
模块路径解析规则
require
函数支持斜杠(/
)或盘符(C:
)开头的绝对路径,也支持./
开头的相对路径。但这两种路径在模块之间建立了强耦合关系。
require
函数支持第三种形式的路径,写法类似于foo/bar
,并依次按照以下规则解析路径,直到找到模块位置。
- 内置模块
- node_modules目录
- NODE_PATH环境变量
包(package)
我们已经知道了JS模块的基本单位模块是单个JS文件,但复杂些的模块往往由多个子模块组成。
为了便于管理和使用,我们可以把由多个子模块组成的大模块称做包
,并把所有子模块放在同一个目录里。
在组成一个包的所有子模块中,需要有一个入口模块,入口模块的导出对象被作为包的导出对象。
index.js
当模块的文件名是index.js
,加载模块时可以使用模块所在目录的路径代替模块文件路径
var cat = require('/home/user/lib/cat');
var cat = require('/home/user/lib/cat/index');
package.json
如果想自定义入口模块的文件名和存放位置,就需要在包目录下包含一个package.json
文件,并在其中指定入口模块的路径。
NodeJS会根据包目录下的package.json
找到入口模块所在位置
工程目录
一个标准的工程目录都看起来像下边这样
- /home/user/workspace/node-echo/ # 工程目录
- bin/ # 存放命令行相关代码
node-echo
+ doc/ # 存放文档
- lib/ # 存放API相关代码
echo.js
- node_modules/ # 存放三方包
+ argv/
+ tests/ # 存放测试用例
package.json # 元数据文件
README.md # 说明文件
NPM
NPM是随同NodeJS的包管理工具
下载三方包
下载好之后,argv
包就放在了工程目录下的node_modules
目录中,因此在代码中只需要通过require('argv')
的方式就好,无需指定三方包路径。
用户只需关心自己直接使用的三方包,不需要自己去解决所有包的依赖关系
发布代码
第一次使用NPM发布代码前需要注册一个账号
终端下运行npm adduser
,之后按照提示做即可。账号搞定后,接着我们需要编辑package.json
文件,加入NPM必需的字段。
{
"name": "node-echo", # 包名,在NPM服务器上须要保持唯一
"version": "1.0.0", # 当前版本号
"dependencies": { # 三方包依赖,需要指定包名和版本号
"argv": "0.0.2"
},
"main": "./lib/echo.js", # 入口模块位置
"bin" : {
"node-echo": "./bin/node-echo" # 命令行程序名和主模块位置
}
}
之后,我们就可以在package.json
所在目录下运行npm publish
发布代码了。
文件操作
让前端觉得如获神器的不是NodeJS能做网络编程,而是NodeJS能够操作文件。小至文件查找,大至代码编译,几乎没有一个前端工具不操作文件。换个角度讲,几乎也只需要一些数据处理逻辑,再加上一些文件操作,就能够编写出大多数前端工具。
开门红
小文件拷贝
使用NodeJS内置的fs
模块
大文件拷贝
上边的程序拷贝一些小文件没啥问题,但这种一次性把所有文件内容都读取到内存中后再一次性写入磁盘的方式不适合拷贝大文件,内存会爆仓。对于大文件,我们只能读一点写一点,直到完成拷贝
API走马观花
Buffer(数据块)
buffer 缓冲/
JS语言自身只有字符串数据类型,没有二进制数据类型,因此NodeJS提供了一个与String
对等的全局构造函数Buffer
来提供对二进制数据的操作。
Buffer
与字符串有一个重要区别。字符串是只读的,并且对字符串的任何修改得到的都是一个新字符串,原字符串保持不变。至于Buffer
,更像是可以做指针操作的C语言数组
Stream(数据流)
当内存中无法一次装下需要处理的数据时,或者一边读取一边处理更加高效时,我们就需要用到数据流
File System(文件系统)
NodeJS通过fs
内置模块提供对文件的操作。fs
模块提供的API基本上可以分为以下三类:
-
文件属性读写。
其中常用的有
fs.stat
、fs.chmod
、fs.chown
等等。 -
文件内容读写。
其中常用的有
fs.readFile
、fs.readdir
、fs.writeFile
、fs.mkdir
等等。 -
底层文件操作。
其中常用的有
fs.open
、fs.read
、fs.write
、fs.close
等等。
基本上所有fs
模块API的回调参数都有两个。第一个参数在有错误发生时等于异常对象,第二个参数始终用于返回API方法执行结果。
Path(路径)
操作文件时难免不与文件路径打交道。NodeJS提供了path
内置模块来简化路径相关操作,并提升代码可读性。
path.normalize
将传入的路径转换为标准路径,具体讲的话,除了解析路径中的.
与..
外,还能去掉多余的斜杠。
path.join
将传入的多个路径拼接为标准路径。该方法可避免手工拼接路径字符串的繁琐,并且能在不同系统下正确使用相应的路径分隔符
path.extname
当我们需要根据不同文件扩展名做不同操作时,该方法就显得很好用。
遍历目录
递归算法
遍历算法
同步遍历
异步遍历
文本编码
使用NodeJS编写前端工具时,操作得最多的是文本文件,因此也就涉及到了文件编码的处理问题。
我们常用的文本编码有UTF8
和GBK
两种,并且UTF8
文件还可能带有BOM。
在读取不同编码的文本文件时,需要将文件内容转换为JS使用的UTF8
编码字符串后才能正常处理。
BOM的移除
GBK转UTF8
单字节编码
网络操作
API走马观花
http
'http'模块提供两种使用方式:
-
作为服务端使用时,创建一个HTTP服务器,监听HTTP客户端请求并返回响应。
-
作为客户端使用时,发起一个HTTP客户端请求,获取服务端响应。
HTTPS
https
模块与http
模块极为类似,区别在于https
模块需要额外处理SSL证书
URL
处理HTTP请求时url
模块使用率超高,因为该模块允许解析URL、生成URL,以及拼接URL
Query String
querystring
模块用于实现URL参数字符串与参数对象的互相转换
Zlib
zlib
模块提供了数据压缩和解压的功能。
当我们处理HTTP请求和响应时,可能需要用到这个模块。
Net
net
模块可用于创建Socket服务器或Socket客户端
进程管理
NodeJS可以感知和控制自身进程的运行环境和状态,也可以创建子进程并与其协同工作,这使得NodeJS可以把多个程序组合在一起共同完成某项工作,并在其中充当胶水和调度器的作用。
开门红
我们已经知道了NodeJS自带的fs
模块比较基础,把一个目录里的所有文件和子目录都拷贝到另一个目录里需要写不少代码。
Process
process
不是内置模块,而是一个全局对象
Child Process
Cluster
应用场景
异步编程
NodeJS最大的卖点——事件机制和异步IO,对开发者并不是透明的。
回调
在代码中,异步编程的直接体现就是回调。异步编程依托于回调来实现,但不能说使用了回调后程序就异步化了。
JS本身是单线程运行的,不可能在一段代码还未结束运行时去运行别的代码,因此也就不存在异步执行的概念。
但是,如果某个函数做的事情是创建一个别的线程或进程,并与JS主线程并行地做一些事情,并在事情做完后通知JS主线程,那情况又不一样了。
代码设计模式
域(Domain)
NodeJS提供了domain
模块,可以简化异步代码的异常处理
在介绍该模块之前,我们需要首先理解“域”的概念
NPM
node package manager,是一个NodeJS包管理和分发工具,已经成为了非官方的发布Node模块(包)的标准。
Nodejs自身提供了基本的模块,但是开发实际应用过程中仅仅依靠这些基本模块则还需要较多的工作。幸运的是,Nodejs库和框架为我们提供了帮助,让我们减少工作量。但是成百上千的库或者框架管理起来又很麻烦,有了NPM,可以很快的找到特定服务要使用的包,进行下载、安装以及管理已经安装的包。
If you've been working with Javascript for awhile, you might have heard of npm: npm makes it easy for Javascript developers to share the code that they've created to solve particular problems, and for other developers to reuse that code in their own applications.
Once you're depending on this code from other developers, npm makes it really easy to check to see if they've made any updates to it, and to download those updates when they're made.(可以检测所依赖的代码块是否有更新)
These bits of reusable code are called packages, or sometimes modules. A package is just a directory with one or more files in it, that also has a filed called "package.json" with some meta data about this package.
A typical application, such as a website, will depend on dozens or hundreds of packages. These packages are often small. The general idea is that you create a small building block which solves one problem and solves it well. This makes it possible for you to compose larger, custom solutions out of these small, shared building blocks.
So now that you have an idea of what npm can do, let's talk about how it works. When people talk about npm, they can be talking about one of three things. They could be talking about the website, which we've just been looking at. Or they could be talking about the registry, which is a big database of information about packages that people are sharing. Or the third thing they could be talking about is the client: when a developer decides to share their code, they use the npm client which is installed on their computer to publish that code up to the registry. And once there's an entry for this package in the registry, then other developers can use their npm clients to install the package from the registry. The entry in the registry for this package is also reflected on the website, where there's a page dedicated to this new package.(人们讨论npm,是在讨论三件事中的一件,一是本网站(官网),二是仓库(或是代码库),三是客户端上的行为)
So that's what npm is. It's a way to reuse code from other developers, and also a way to share your code with them, and it makes it easy to manage the different versions of code.
Node.js REPL(Read Eval Print Loop:交互式解释器) 表示一个电脑的环境,类似 Window 系统的终端或 Unix/Linux shell,我们可以在终端中输入命令,并接收系统的响应。
Node 自带了交互式解释器,可以执行以下任务:
-
读取 - 读取用户输入,解析输入了Javascript 数据结构并存储在内存中。
-
执行 - 执行输入的数据结构
-
打印 - 输出结果
-
循环 - 循环操作以上步骤直到用户两次按下 ctrl-c 按钮退出。
淘宝 NPM 镜像
这是一个完整 npmjs.org
镜像站,你可以用此代替官方版本(只读),同步频率目前为 10分钟 一次以保证尽量与官方服务同步
安装模块
cnpm install [name]