Appearance
总览
- nodejs安装和环境设置
- npm包管理工具使用
- nodejs生态和常用标准库
nodejs安装和环境配置
nodejs的版本现在已更新到8.0,此版本于2017年成为最新的LTS(Long Term Support)版本,即长期维护版本,维护周期为2年,上一个LTS版本为6.0,会于2018年结束维护期,下图为nodejs版本的发布周期图
6.0版本虽然已经支持很多es6/7的语法特性,但最新的LTS为8.0版本,意味着8.0版本已经是稳定可靠的版本,完全可以在生产环境中使用,并且8.0版本支持更多的语法特性,性能和内存安全性等方面有很大提升,因此推荐开发和部署时都可以使用8.0版本。
nodejs的安装包分两种:
.msi直接安装,并自动设置好环境变量,不过一般不推荐此安装方式
.zip解压缩到某目录并配置环境变量
推荐以压缩包的方式安装,可以自由配置环境变量、全局安装包的安装位置,便于对包和工具库的维护,
并且可以同时安装多个版本而不产生冲突。
下面主要介绍以压缩包的方式安装时的环境配置(所有的配置都是针对windows系统环境的)。
配置NODE_HOME路径为解压缩后node.exe所在的目录,并将此变量名加入到path中: ;%NODE_HOME%; 。
此变量名可自定义,对node和npm没有用途(有一些环境变量对node的npm有特殊用途,后面会介绍到),变量名越直观越好。
将node的运行时加入到环境变量中后,其实就已经可以在控制台使用node了,同时由于npm.cmd是和node.exe在同一个目录下,npm包管理工具也可以直接使用了。但为了能更好的管理全局安装包或者你不想将全局安装包都放在用户目录下(npm默认的全局安装包在%USER%\AppData\Roaming\npm目录,若你没有用户目录下的管理权限安装全局依赖包是会产生错误的,缓存目录在%AppData%\npm-cache),使用以下配置来设置npm依赖包的全局配置和缓存目录:
bash
npm config set prefix “D:\apps\nodejs\node_modules\node_global”
# 配置npm的全局安装包目录,比如 npm i -g pm2 后,pm2 将安装到此目录下,
# 因此此目录也需要配置在环境变量中
npm config set cache “D:\apps\nodejs\node_modules\node_cache”
# 不管时安装全局包还是在某个项目目录下安装包,npm都会将包下载缓存在此目录下,
# 并会对不同版本进行区分,下次安装同样的包时可以提升速度
更改以上配置也可以通过修改 %USER%/.npmrc 配置文件来完成。
下载nodejs的依赖包时,由于npm仓库在国外,经常会遇到下载缓慢或下载不到依赖包的问题,此时若能有一个国内的服务器提供npm包的下载就好了,好在淘宝的nodejs程序猿们也遇到了这样的麻烦,在他们强大技术的加持下,他们在国内搭建了npm的镜像源,并向广大nodejs开发者免费开放了npm镜像源的服务(http://npm.taobao.org/)。淘宝的镜像源目前每十分钟与官方源同步一次,这样的同步速率足够保证你通过淘宝镜像源下载的依赖包不会出现版本不一致问题,配置了镜像源后,在你使用npm时的其它命令完全不受影响,如丝般顺滑。那么如何能品尝到如此🍩美味的镜像源呢?哈哈,很简单,只需进行如下配置:
bash
npm config set registry https://registry.npm.taobao.org
npm config get registry # 来查看配置是否成功
或者你也可以使用淘宝的npm定制版cnpm,在使用上和原版npm没有区别,只是在执行命令时将npm改为cnpm
bash
npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm install -g pm2 # 使用时将npm改为cnpm
上面这写配置都会修改%USER%.npmrc文件,若安装了多个npm,切换不同的版本,npm都会读取这个文件的配置,所以只用进行一次配置,对所有npm都是生效的。
npm包管理工具使用
npm一些常用命令介绍
bash
npm install koa
# 在当前目录下安装koa依赖包,koa包将保存在当前目录下的node_modules目录下
# -d 参数将会显示安装过程
npm i koa
# 同上,install的简写
npm install koa -S 或者 npm install koa --save
# 若当前目录下存在规范的 package.json 文件,会将koa依赖写在dependencies配置下,若不存在
# package.json 文件,则只会将依赖包保存在node_modules目录下,在最新npm版本中,安装依赖时会
# 默认save
npm install mocha -D 或者 npm install mocha --save-dev
# 同上,会将依赖写在devDependencies配置下
npm install
# 当前目录下存在package.json,将会下载dependencies和devDependencies配置下的依赖包
npm install --production 或者 NODE_ENV=production npm install
# 将会只安装当前目录下存在package.json中dependencies配置下的依赖,在生产环境下不需要开发依
# 赖,比如一些预编译工具,打包工具和测试工具
npm uninstall koa
# 删除node_modules目录下的koa包及其依赖,不会影响其它库的依赖,npm uninstall 不指定包,将什么
# 都不会发生
npm uninstall koa -S 或 npm install mocha -D
# 同上,并且会删除dependencies或devDependencies下的配置
npm update koa
# 更新版本
npm init
# 在当前目录下初始化package.json文件
npm start
# 执行package.json文件内scripts配置下的start对应的命令
npm run test
# 执行package.json文件内scripts配置下的test对应的命令,可以在scripts配置下设置任意名称的命令
npm version major / minor / patch
# 升级package.json文件的version配置,major主版本升级,minor小版本升级,patch修复版本升级
npm vesrion
# 查看项目及其环境的版本,包括当前项目,npm,nodejs,v8(js解析引擎)等的版本
npm help
# 查看npm帮助说明和可以使用到的命令
npm xxx -h
# 查看某个命令的帮助说明
npm -v
# 查看npm版本
在上面npm常用命令介绍中,我们可以看出来npm是和package.json配置文件紧密配合使用的,package.json中的内容是标准的json格式,意味着不能包含注释,初学者在刚开始使用时会习惯在此文件内写注释内容,这样会导致使用npm和运行nodejs是报错,所有内容都包含在一对大括号内。package.json 需要放在项目的根目录下,用于定义包的属性。使用npm和nodejs都会用到此文件。下面就来介绍下常用的package.json配置。
main,配置一个文件路径,此文件将作为此模块的入口文件,在nodejs加载模块时,会优先读取此配置,若不存在此配置,则会加载相同目录下的index.js文件。
scripts,配置一些快捷命令(也就是可以在控制台中执行的命令),如 "start": "node index.js",使用npm run xxx执行相应命令,其中start配置可以使用npm start快捷执行,这个配置在预编译或测试等使用场景下非常有用,如:可以指定运行时以全局库来运行,pm2 start xxx,可以配置环境变量NODE_ENV=production (linux下的方式),配置运行时参数 node --port。在程序中使用process.argv.xxx来获取参数,process.env.xxx来获取环境变量。这些复杂的命令和配置都可以浓缩在一个命令下,方便实用,就是如此清爽。
dependencies,配置运行时依赖,模块版本的说明请点击查看
devDependencies,配置开发依赖,在生产环境中此处用的的模块都不需安装,因此在配置依赖时要区分好运行时依赖和开发依赖,这两种依赖配置对运行没有影响,都会安装在node_modules目录下,只是做好这种区分,可以减小生产环境下依赖包的整体大小。
name,模块名称,与当前模块的目录名称一致,在require时nodejs是按照目录名称来查找模块的。并且也是作为模块发布时的名称。在其它项目中配置依赖时会用到此名称。
version,模块的版本,在配置依赖时与name配合使用
node和npm的两个环境变量
NODE_PATH 这个环境变量是给nodejs使用的,在加载模块时,nodejs会从当前目录递归查询到根目录,若还找不到,则最后会在此变量配置的目录下继续查找。多个目录之间用分号分隔:
bash
NODE_PATH="/usr/lib/node_modules;/usr/local/lib/node_modules"
此变量通常设置为npm全局安装包的目录,这样可以重用全局安装的模块。
NODE_ENV 这个变量是给npm使用的,当然,在nodejs程序中也是可以访问到的 process.env.NODE_ENV,此变量可以控制npm的行为,如配置NODE_ENV=production,在安装依赖时只会安装直接依赖而不会安装开发依赖。
有时候nodejs执行一些新语法或函数,需要使用'use strict'严格模式,在运行时对所有文件使用严格模式可以这样 node index.js --use_strict,使用严格模式还可以提升性能。
升级和多版本
多版本和升级nodejs可以使用一些版本管理工具,如:nvm,n等。这里主要介绍下多版本的原理:
查看与node.exe在同一个目录下的包管理工具npm.cmd可以发现,npm运行时就是使用node来运行当前目录下的npm项目,其项目接口与普通的node模块没有任何区别,都是放在node_moules,node依赖的查找路径下的。由此看出来node.exe就是一个绿色的可执行文件,可以随意拷贝,不会有依赖问题。
弄清了他们的本质后,就可以通过设置环境变量到不同的node版本目录下来管理多个node版本了。
nvm 独立于node安装,即不依赖于nodejs和npm,在windows环境下通过link来切换版本,因此需要将link目录设置到环境变量中,同时将nvm程序所在目录也加入到path中,免安装使用的方式下会读取setting.txt配置文件,在此配置文件内做如下配置,mirror指定镜像源,指定淘宝源避免下载不到的问题。看nvm的install.cmd会将NVM_SYSLINK这个环境变量赋值到path中,直接修改path配置却不会影响link的创建位置,nvm仍是读取NVM_SYSLINK这个环境变量,因此需创建这个环境变量,指向你要配置的link位置,然后将此变量加入到path中,这样运行node命令时就能找到了。
txt
root: E:\Node\nvm
path: E:\Node\nodejs
arch: 64
proxy: none
node_mirror: https://npm.taobao.org/mirrors/node/
npm_mirror: https://npm.taobao.org/mirrors/npm/
nodejs生态和常用标准库
nodejs生态
https://www.npmjs.com/
这个网站相信做node开发的都会知道,不知道的改进打开看看,这可是必会知识点哦。为了保证node第三方库的安全,避免碎片化,能够统一管理,这种唯一的存放所有第三方库由官方统一维护的网站应用而生,这一举措使nodejs的生态得以快速成长,作为目前最成功和稳定的包管理方案,这种模式成为了其它现代编程语言的开发典范。
nodejs的官方仓库,当你开发中遇到问题时,issues讨论中说不定可以找到对应的解决办法,一些新功能和bug修复也会由issues提出来供社区一起讨论,很多问题提出来都能很快得到社区或基金会开发人员的及时出来。node基金会也经常会举办官方技术讨论活动,国内也有一些社区自发组织的技术分享会,若你有机会参加的话,可以一睹大牛的风采,像阿里的一些nodejs攻城狮都是社区的活跃人物,像最近阿里的年轻漂亮的美女技术大牛张秋怡被nodejs社区吸纳为CTC(核心技术委员会)成员,可以说nodejs在维护社区活跃度做的非常出色,这也是其能蓬勃发展的一个原因。
在awesome-node上介绍了很多,nodejs开发能够触及到的领域,像桌面应用(nodejs与H5技术构建的桌面应用开发环境electron),游戏,网络应用,爬虫,命令行工具,工程构建工具,编译工具等等,nodejs凭借其开发效率和优异的性能,几乎已经能做我们遇到的各种场景的开发,并且为了将js发扬广大,react-native可以将js用于移动应用领域的开发,cylon,ruff等使js在智能硬件控制中的应用得以发扬广大。就像js社区广为流传的一句话:一切可以用js开发的,最终都会用js开发。嘿嘿嘿,这可不是吹牛逼哦,有兴趣的同学可以尝试在不同领域去玩一玩,体会下js的魅力✨
常用标准库介绍
fs 文件系统,用于执行文件操作,并且多数api都提供了同步(在异步的方法后加Sync)和异步的操作,常用方法有:
mkdir 创建目录
rmdir 移除目录
rename 重命名
exists 判断文件是否存在
stat 检查文件是否存在,并获取文件元数据,如创建修改时间,文件大小等
readFile 读取文件
writeFile 写入文件,若存在则会替代已存在文件
appendFile 在某文件后面继续写入内容
unlink 删除文件
拷贝文件的各种姿势:
js
// 异步方式
fs.readFile('./file', (err, data) => {
fs.writeFile('./dir/file', data, err => if(err) console.log(err))
})
// 同步方式
fs.writeFileSync('./dir/file', fs.readFileSync('./file'));
// 异步流,readFile 和 writeFile 的copy方式会将文件整个读取到内存中再写入到目标文件,不适合对
// 大文件的copy,对大文件的操作应使用流的操作方式,读取一点写入一点,这样不会占用过多内存。
fs.createReadStream('./file').pipe(fs.createWriteStream('./dir/file'));
对于文件系统的路径:
只有 require 的路径是相对当前文件,其他大部分函数接收的路径都是相对于「当前工作目录」即程序运行时的 cwd,文件读取路径也是这样子的。
http 用于提供http服务,包括链接创建,处理请求和响应和发送http请求
createServer 创建http服务
request 发起http请求
get http请求的便捷方法,使用get方式发起请求
创建一个http服务,监听80端口:
js
http.createServer((req, res) => {
res.writeHead(200, {'Content-type' : 'text/html'});
res.write('<h1>Node.js</h1>');
res.end('<p>Hello World</p>');
}).listen(80);
net,dgram 用于处理tcp和udp通信,大多互联网应用使用http协议进行通信(http基于tcp)已经可以满足功能上的需求。但像游戏服务,即时通信服务则需要用到tcp和udp通信协议。nodejs通过net和dgram分别提供了对tcp和udp协议的处理功能。
简单点说,tcp是需要建立信道(称为三次握手协议)后才会发送数据,tcp协议有一套对数据完整性的处理机制,如分片(帧)传输后数据按顺序还原,损坏数据重发,接收成功的响应,通信信道的保持等,而udp则会像发送广播一样,不需要建立信道,发送方只管发送数据,接收方无法确认数据的完整性,也不会有自动的重发机制,不过由于udp不需要耗费资源在信道的建立上,并且适用于网络状况不好的情况,所有有些即时通信工具会使用udp来模拟tcp的一些特性,如数据重发(udp发送时多发送几次),数据完整性保障(接收方向发送方也发送udp)等。
网络模型,tcp,udp的介绍
stream 流对象的操作,像文件流,网络流,Stream是一个抽象类型,像文件流和网络流都是它的实现类
read 读取流,Readable
write 写入流,Writable
pipe 管道,将读写流串起来
常用的就是像上面提到的文件拷贝的方式。
buffer 用于处理二进制数据,像流的处理,图片等二进制数据的处理,在es6之前js是不支持二进制处理的,nodejs提供了更友好的二进制处理类Buffer
crypto 非常强大的加密解密操作模块,支持以各种姿势加解密。AES对称加密,RSA非对称加密,生成公钥私钥对。
talk is cheap,show me the code。废话不多说,来,看代码,最常用的对称加解密:
js
const crypto = require('crypto');
const text = '我是明文';
const cipher = crypto.createCipher('aes-128-ctr', '我是密码'); // 提供算法和加密的key
let crypted = cipher.update(text, 'utf8', 'hex'); // 指示明文是utf8编码,生成的密文进行十六进
//制编码
crypted += cipher.final('hex'); // 最后的密文再加一个十六进制编码结束符
console.log(crypted); // 输出密文
const decipher = crypto.createDecipher('aes-128-ctr', '我是密码'); // 提供算法和解密的key
let decrypted = decipher.update(crypted, 'hex', 'utf8'); // 指示密文是十六进制编码,解密的明
//文是utf8编码
decrypted += decipher.final('utf8'); // 最后的明文再加一个utf8编码结束符
console.log(decrypted); // 输出明文
path 提供了很多实用的处理文件和目录路径的方法
join 将多个字符串拼接成一个合法路径
parse 将一个路径转义为对象
format 将路径对象转成路径字符串
extname 获取文件扩展明
isAbsolute 判断是否是绝对路径
resolve 将一个路径解析为绝对路径,进入到第一个目录将后面的目录参照此目录(相对或绝对)生成绝对路径
url 用于url的处理与解析,querystring 用于解析与格式化 URL 查询字符串
这两个模块提供了url对象转字符串,字符串转url对象,还有url属性的获取,如host,port等等,查询参数的解析。
util 实用的工具方法,很多判断对象是否是某类型的方法被废弃了,使用es标准提供的判断方式或typeof,instanceof。
promisify 是util模块提供的重要的方法,用以将异步方法封装成Promise对象,这样就可以用在async/await函数中了
events 由于nodejs的异步特性,很多方法都是回调式的,为了避免过深的回调和系统设计时的解耦合,大多异步操作方式都实现了事件触发模式。
on 监听某事件名
emit 触发某事件名
addListener on的别名
global nodejs中一个文件对应一个模块,每个模块都有一个全局对象global,其中的属性和方法可以在此模块中直接访问。当然可全局访问的还包括es标准定义的所有全局对象。
主要有: exports , module ,process, require 这几个,写模块时都会用到,其基本概念不多说,主要说下 setImmediate,这个函数和process.nextTick()涉及到nodejs中的事件轮询机制,将会在事件轮询章节介绍。简单说一下,setImmediate 设置立即执行函数,此函数会在本次事件轮询(事件轮询分多个阶段)的check阶段执行,setImmediate设置的回调会以链表的解构存储起来,因此每次只会取链表的第一个来执行,每次只执行一个回调函数。
process 控制当前进程的行为,主要说一下nextTick,此方法会将回调放置在一个数组中,在本次事件轮询的每个阶段之前执行,即在此阶段设置了nextTick,在下一个阶段之前就会执行nextTick,此数组有回调就会在每个阶段前都进行执行,为了使其它回调函数有执行机会,nextTick缺省最大回调次数不超过1000。
因此nextTick会比setImmediate先执行。
在全局变量中,有几个变量是用来获取运行时模块的路径或者运行时的工作目录
__diranme 当前模块的文件所在目录
__filename 当前模块的文件路径
process.cwd() 当前程序的工作目录,也就是执行node xxx.js时所在的目录
例如:
js
// /dir/file/file.js
require('./m/module.js');
console.log(__dirname);
console.log(__filename);
console.log(process.cwd());
// /dir/file/m/module.js
console.log(__dirname);
console.log(__filename);
console.log(process.cwd());
// 在/dir/file目录下执行 node file.js输出
/dir/file/m
/dir/file/m/module.js
/dir/file
/dir/file
/dir/file/file.js
/dir/file
// 在/dir/目录下执行 node ./file/file.js输出
/dir/file/m
/dir/file/m/module.js
/dir
/dir/file
/dir/file/file.js
/dir
// 在/dir/file/m目录下执行 node /dir/file/file.js输出
/dir/file/m
/dir/file/m/module.js
/dir/file/m
/dir/file
/dir/file/file.js
/dir/file/m
child_process 开启和控制子进程,并控制进程间的通信。这两篇文章介绍的比较详细,我这里就不啰嗦了,Node.js中的child_process及进程通信Node.js进程通信模块child_process。
cluster 集群,利用多核提升应用性能,感兴趣的同学可以看下这篇博文解读Nodejs多核处理模块cluster。