——该文档用于node.js基本功能、安装步骤和环境配置的
学习以及交流
一、 Node.js内容简介
1、当前的服务器程序有什么问题?
在 Java和 PHP 这类语言中,每个连接都会生成一个新线程,每个新线程可能需要 2 MB 的配套内存。在一个拥有 8 GB RAM 的系统上,理论上最大的并发连接数量是 4,000 个用户。随着您的客户群的增长,如果希望您的 Web 应用程序支持更多用户,那么,您必须添加更多服务器。当然,这会增加服务器成本、流量成本和人工成本等成本。除这些成本上升外,还有一个潜在技术问题,即用户可能针对每个请求使用不同的服务器,因此,任何共享资源都必须在所有服务器之间共享。鉴于上述所有原因,整个 Web 应用程序架构(包括流量、处理器速度和内存速度)中的瓶颈是:服务器能够处理的并发连接的最大数量。也就是说,用户请求到来后,Java等语言会为其分配一个线程来处理,此时这个线程就只能处理该请求,并且需要一直维护该请求所需要的资源直到响应才会释放资源;如果并发量很大,就会造成后面的请求处于阻塞状态。 2、NodeJS如何解决上述问题?
NodeJS采用了不同的方式来处理请求。它每接收到一个请求就会触发一个事件,并且将该事件加入到事件队列中,紧接着又以同样的方式去处理下一个请求;这样能够保证每一个请求都被及时处理(“处理”:指被加入到事件队列的过程),不会阻塞后面的请求。同时NodeJS引擎会调度事件队列中的任务,执行这些任务,最后将结果响应给用户。
即更改连接到服务器的方式,每个连接会触发一个事件,NodeJS引擎会把该事件放入到事件队列中,而不是为每个连接分配一个OS线程及其配套内存空间。(注意:维护事件队列本身也是需要成本的,而且事件队列越长,得到响应的事件就越长,并发量上去还是会力不从心。)
3、Node.js使用了V8引擎
V8 引擎是 Google 用于其 Chrome 浏览器的底层 JavaScript 引擎,负责解释并执行JS代码,并且内置了一个用 C++ 编写的超快解释器;最值得一提的是V8引擎可以被嵌入其他任何应用程序,并不仅限于在一个浏览器中运行。NodeJS的作者也正是看中这一点,将其作为NodeJS的核心引擎。
二、 Node.js下载、安装、环境搭建
第一步、windows下的NodeJS下载(v0.6.0版本之后,支持windows native),只需要登陆Node.js中文官网(http://nodejs.cn/),便可以看到:
第二步、安装。这里我们使用v4.2.4版本,安装比较简单直接点击install就可以安装了,安装过程基本直接“NEXT”就可以了。(windows的安装msi文件在过程中会直接添加path的系统变量,变量值是你的安装路径,例如“C:\\Program Files\\nodejs”)
第三步、测试。安装完成后可以使用cmd(win+r然后输入cmd进入)测试下是否安装成功。方法:在cmd下输入node -v,出现下图版本提示就是完成了NodeJS的安装。
第四步、npm的安装。由于新版的NodeJS已经集成了npm,所以之前npm也一并安装好了。同样可以使用cmd命令行输入\"npm -v\"来测试是否成功安装。如下图,出现版本提示便OK了。
第五步。常规NodeJS的搭建到现在为止已经完成了,急不及待的话你可以在”cmd“输入”node“进入node开发模式下,输入你的NodeJS第一句:”hello world“ - 输入:console.log('hello world')。
我们要先配置npm的全局模块的存放路径以及cache的路径,例如我希望将以上两个文件夹放在NodeJS的主目录下,便在NodeJs下建立\"node_global\"及\"node_cache\"两个文件夹。如下图
例如Node.js的地址是C:\\Program Files\\nodejs启动cmd 则输入:
npm config set prefix \"C:\\Program Files\\nodejs\\node_global\" 以及
npm config set cache \"C:\\Program Files\\nodejs\\node_cache\"
当然这个可以不用配置
第六步。 模块的下载和安装。选择express这个模块。同样在cmd命令行里面,输入“npm install express -g”(“-g”这个是全局安装的意思,也就是上面说设置的“C:\\Program Files\\nodejs\\node_global”里面。)。待cmd里面的安装过程滚动完成后,会提示“express”装在了哪、版本还有它的目录结构是怎样
第七步。模块的全局安装与本地安装。npm 的包安装分为本地安装(local)、全局安装(global)两种,从敲的命令行来看,差别只是有没有-g而已,比如 npm install express # 本地安装 npm install express -g # 全局安装
第八步。环境变量设置,打开系统对话框,“我的电脑”右键“属性”-“高级系统设置”-“高级”-“环境变量”。如下图:
设置环境变量:变量名:NODE_PATH
值:D:\\Program Files\\nodejs\\node_global\\node_modules
注意:因为我是把nodejs安装在D:\\Program Files\\目录下,所以环境变量就这样设置的D:\\Program Files\\nodejs\\node_global\\node_modules
注:最新版nodejs安装版已经不需要进行环境变量设置了 直接可以在运行里面使用 node 和 npm 命令
第九步。模块卸载。我们可以使用以下命令来卸载 Node.js 模块。 $ npm uninstall express
卸载后,你可以到 /node_modules/ 目录下查看包是否还存在,或者使用以下命令查看: $ npm ls
三、 用Node.js构建的项目结构
通常使用express-generator模块来快速创建一个应用骨架,然后再在此基础上做一些适
当的调整即可。
用法:
1. 全局安装express-generator 2. 新建一个文件夹用于存放项目 3. 在该文件夹下,执行如下命令:
express –e myProject
4. 成功执行后,可以在该文件夹下发现新生成了一个名为myProject的工程
目录说明:
bin --->存放NodeJS项目的启动脚本;
public --->存放静态资源,如图片、css和js文件等; routes --->存放自定义路由;
views --->存放模板文件,如ejs、jade;
app.js --->该文件包含了一些express基本路由规则;
package.json --->描述项目工程信息,如项目名称、版本、依赖模块等;
这个结构不符合我们现在开发需要,所以需要调整一下:
目录说明:
app/cache-->存放缓存方法;
app/controller-->存放处理业务逻辑的文件; app/model-->存放实体类; app/util-->存放各种工具脚步; bin --->存放NodeJS项目的启动脚本; logs --->存放应用程序日志; config-->存放项目配置文件;
public --->存放静态资源,如图片、css和js文件等; public/lib --->存放前端第三方插件; routes --->存放自定义路由; test --->存放测试用例;
utils --->存放工具类,如日志工具类、日期工具类; views --->存放模板文件,如ejs、jade;
app.js --->该文件包含了一些express基本路由规则;
package.json --->描述项目工程信息,如项目名称、版本、依赖模块等;
四、 项目构建和部署
1、Less文件要用使用gulp 命令编译成css文件 2、项目部署分为:手动部署和自动部署。 手动部署
1、通过ssh登录服务器 2、进入nodejs目录
3、执行:git pull 命令拉取最新代码 4、执行:npm install 安装新依赖
5、执行:pm2 restart all 重新启动nodejs进程
自动部署
使用Jenkins来实现自动部署。当新的代码被合并到仓库后,可以自动触发Jenkins编译,执行单元测试,然后将构建结果自动部署到应用服务器
五、 Node.js常用技术点、常用命令
1. npm
npm是NodeJS的包管理器,通常我们在安装nodejs的时候都会自带该命令工具。主要用于安装或卸载第三方模块。
安装到当前目录:npm install MODULE_NAME –save或npm install MODULE_NAME –save-dev
全局安装:npm install MODULE_NAME –g
2. cnpm
由于国内的网络环境不稳定,经常无法正常下载某些模块,因此淘宝建立了一个npmjs.org镜像,并定制了一个命令行工具cnpm用于开发人员下载资源。
安装cnpm:npm install -g cnpm --registry=https://registry.npm.taobao.org。 使用cnpm:用法同npm命令。
3. node
node命令主要用于执行js文件。例如:node app.js。更多用户可以通过输入node –help
命令来查看。
六、 nodejs常用模块
NodeJS中常用的模块主要有:http、body-parser、cookie-parser、path、util、fs、events、async、express、ejs、log4js、mysql、eventproxy和gulp等。
1. http
要使用HTTP服务器或客户端功能,需引用此模块。 常用APIs:
http.createServer([requestListener]):
创建并返回一个web服务器对象。
server.listen(port, [hostname], [backlog], [callback]):
监听指定端口,其中server为createServer()方法所创建的web服务器对象。 http.request(options, callback):
创建并返回一个http request请求实例。 req.write(data):
发送数据。其中req为http request请求实例。 req.end():
使用http.request()方法时都必须总是调用req.end()以表明这个请求已经完成,即使响应body里没有任何数据。 示例:
API链接:
http://nodeapi.ucdok.com/api/http.html#http_request_write_chunk_encoding_4837
2. body-parser
第三方模块,用于解析客户端发来的请求中body部分的内容,包括:JSON解析处理和URL编码处理。之前是express模块的一个中间件,现在分离出来成为了一个模块。实际应用中也还是与express配合使用。 常用APIs:
bodyParser.json():
bodyParser.urlencoded(options): 示例:
3. cookie-parser
第三方模块,用于获取web浏览器发送的cookie中的内容。它会解析header中的cookie,并将解析后的结果填充到req对象的cookies属性中。 示例:
4. path
预置模块,用于处理目录,提高开发效率。 常用APIs:
path.normalize():
将不符合规范的路径格式化,简化开发人员中处理各种复杂的路径判断。
path.join(PATH1,PATH2,…):
将所有名称用path.sep串联起来,并调用用normailze()方法格式化。其中path.sep指代的是特定于平台的文件路径分隔符。
5. util
util是一个Node.js 核心模块,提供常用函数的集合,用于弥补核心JavaScript
的功能过于精简的不足。 常用APIs:
util.inherits(constructor, superConstructor):
用于实现对象间原型继承。
util.isArray(obj):
判断obj是否是数组类型。
util.isDate(obj):
判断obj是否是Date类型。
util.isError(obj):
判断obj是否是Error类型
示例:
6. fs
file system是NodeJS的核心模块,用于对文件进行读写操作。 示例:
API链接:http://nodejs.cn/api/fs
7. events
events模块提供了一个十分重要的对象events.EventEmitter。EventEmitter的核心是事件发射与事件监听器。 EventEmitter支持若干个事件监听器。当事件发射时,注册到这个事件的事件监听器被依次调用,事件参数作为回调函数参数传递。
EventEmitter提供了几个简单但很重要的API: emitter.on(event_name, listener):
为名称是event_name的事件注册一个监听器listener。其中emitter为EventEmitter的实例对象。
emitter.emit(event_name, arg1, arg2, …):
触发名称为event_name的事件,并向该事件的监听器传递参数。
emitter.removeListener(event_name, listener_name):
从event_name事件上将listener_name监听器移除。
大多情况不会直接用EventEmitter,而是在对象中继承。原因:首先,具有某个实体功能的对象实现事件符合语义,事件的监听和发射应该是一个对象的方法。其次JavaScript 的对象机制是基于原型的,支持部分多重继承,继承EventEmitter不会打乱对象原有的继承关系。 示例:
8. async
流程控制本来是件比较简单的事,但是由于Nodejs的异步架构的实现方法,
对于需要同步的业务逻辑,实现起来就比较麻烦。嵌套3-4层,代码就会变得的支离破碎了!async就是用于解决流程控制问题的工具包。 常用APIs:
async.waterfall(*func1, func2, …+, callback):
按顺序依次执行一组函数。每个函数产生的值,都将传给下一个。
async.parallel(*func1, func2, …+, callback):
并行执行多个函数,每个函数都是立即执行,不需要等待其它函数先执行。传给最终callback的数组中的数据按照tasks中声明的顺序,而不是执行完成的顺序。
API链接:https://github.com/bsspirit/async_demo
补充:在书写JS代码的时候,我们通常会遇到两种比较常见的场景: #1:各个操作之间是可以并行执行的,只是在最后一步里面需要把他们各自执行的结果整合。针对这种场景,我们可以使用eventproxy.all()或async.parallel()方法来解决。
#2:各个操作之间是需要串行执行并且后一步操作依赖前面操作的返回结果,但由于Node使用的是回调机制,导致程序无法串行执行。针对这种场景,有两个解决方法:
#2.1:回调函数嵌套
这种方式很容易形成回调地狱(callback hell)。 #2.2:使用async模块的async.waterfall()
9. express
express是目前最流行的基于Node.js的Web开发框架,可以快速地搭建一个完整功能的网站。express中有两个概念比较重要:中间件和路由。
路由
将不同的请求分配给相应的处理函数的过程就叫做路由。 示例:
上图中定义了一组路由规则,app代表应用服务器实例。 app.use(pattern, handler1, handler2, …): use():
表示POST和GET请求都可以被接受,若只希望接受POST请求,则可直接使用app.post()方法; pattern
表示对URL的匹配;可以是一个表达式,例如:”/test/*”表示匹配所有URL路径请求中以test开头的请求,这种写法可以匹配无限级路径,但优先级最低;”/test/:id”表示只匹配URL路径以test开头且只有两级的请求;也可以省略不写,表示对于所有请求都直接调用处理函数handlder; handler
表示处理程序,即中间件;
中间件
从概念上来讲,可以简单的看作是一段对http request进行处理的程序。只不过这个“处理程序”可以决定是“直接返回http response”或是“将http request交给下一个中间件”。中间件最大的特点就是:一个中间件处理完,再传递给下一个中
间件。
常用APIs: express():
创建并返回一个应用服务器实例。本质上是对http.createServer的封装。 app.set(name, value):
用于设置变量的值。 示例:
app.set(‘views’, __dirname+’/views’):设置模板文件所在目录。其中views用于指定模板文件所在的目录,res.render方法会需要到该目录中查找模板;__dirname表示当前项目所在路径。
app.set(‘view engine’, ‘ejs’): 用于指定模板文件的后缀,这样就可以使得我们在调用res.render()方法时,第一个参数可以只传入文件名。 app.get(name):
获取设置的变量。 示例:
app.get(‘views’): 获取模板文件所在目录。 app.engine(suffix, handler):
让模板引擎可以识别带有指定后缀的文件。 示例:
app.engine(‘.html’, require(‘ejs’).renderFile):让ejs引擎可以识别.html文件,这样我们就可以直接在html文件里面使用ejs标签。 express.static(path):
指定静态资源存放的路径,如对于静态html页面、js、css、images这类资源的访问,应用服务器就可以直接响应。 示例:
app.use(express.static(__dirname+’/public’)):配置一个静态路由,专门用于处理对静态资源的访问。
10. ejs
ejs是一个开源的Node模板引擎,学习成本低。ejs主要有两种标签:
<% code %>:
用于书写JavaScript 代码。 示例:
注意:示例中的title是从后端传递过来的(后端代码:res.render(‘index’, {title:’test’}))。 <%= code %>:
打印JS变量到页面上。 示例:(见上图)
11. log4js
用于日志记录。log4js的输出级别有6个: trace, debug, info, warn, error, fatal。 logger.trace(); logger.debug(); logger.info(); logger.warn(); logger.error(); logger.fatal(); 示例:
配置信息:
12. moment
moment模块是一个简单易用的轻量级JavaScript日期处理类库,提供了日期格式化、日期解析等功能。它能够将给定的任意日期转换成多种不同的格式,具有强大的日期计算功能,同时也内置了能显示多样的日期形式的函数。
示例:
官网链接:http://momentjs.com/
13. mysql
mysql模块是一个纯nodejs的用javascript实现的一个MySQL客户端程序,封装了对mysql的基本操作。通常我们使用它来做这几件事情:建立数据库连接、
表新删改查、事务处理、连接池配置。
建立数据库连接
使用mysql.createConnection(db_config)方法来创建并返回一个数据库连接。其中,db_config代表数据库连接配置。 示例:
db_config配置信息:
表新删改查
使用conn.query(sql, params, callback)方法来执行sql语句。其中,conn代表数据库连接实例,sql表示要执行的sql语句,params是sql语句中占位符所对应的参数值,callback为sql语句执行完毕后的回调函数。
示例:
事务处理
mysql模块支持connection级别的简单事务处理。 conn.beginTransaction(callback):用于开启事务; conn.commit(callback):用于提交事务; conn.rollback(callback):用于回滚事务; 示例:
连接池创建及配置
在实际项目中,通常使用连接池来管理数据库连接。mysql模块中使用mysql.createPool(pool_config)来创建并返回一个连接池实例,使用pool.getConnection(callback)向连接池申请一个连接。 示例:
连接池配置:
补充:
git链接:https://github.com/felixge/node-mysql,另外推荐一个ORM模块- sequelize
14. eventproxy
eventproxy模块是对events模块的封装,并且也增加了一些新的API,主要用于流程控制避免回调地狱问题。与async模块不同的是,eventproxy采用事件驱动的方式来编写代码。
常用APIs:
eventproxy.create(events, handler, errHandler):
创建并返回一个eventproxy实例。 ep.all(events, handler):
当events事件被触发后,才会执行handler。其中ep表示eventproxy实例;events是事件名称的集合,可以是数组;handler是所有事件都被触
发后才会执行的回调函数。 ep.on(event_name, handler):
为事件添加一个监听器。 ep.emit(event_name, param):
触发指定事件。
ep.after(event_name, times, handler):
当指定事件被触发N次后,才执行handler。其中,times就代表被触发的次数。 示例:
官网链接:http://html5ify.com/eventproxy/api.html
15. supervisor
通过supervisor启动的app应用,每次修改代码后会自动重启。 示例:
补充:forever、supervisor和pm2的区别
forever
forever是一个简单的命令式nodejs的守护进程,能够启动,停止,重启App应用。forever完全基于命令行操作,在forever进程之下,创建node的子进程,通过monitor监控node子进程的运行情况,一旦文件更新,或者进程挂掉,forever会自动重启node服务器,确保应用正常运行。
适用场景:管理多个站点,每个站访问量不大并且不需要监控。 用法:forever start/stop myapp.js
supervisor
一旦有文件更新,立即重启应用程序。 适用场景:开发环境中使用。 用法:supervisor myapp.js
pm2
提供了先进完整的Node多进程管理解决方案。 适用场景:网站访问量比较大,需要完整的监控界面。 用法:
pm2 start/restart/stop myapp.js --->启动/重启/停止myapp应用程序
pm2 logs --->在控制台打印日志
pm2 monit --->监视各个进程的运行状态(CPU占用、内存消耗)
pm2 start myapp.js -i NUM --->以多进程的方式启动应用程序,相当于是创建一
个应用程序集群。其中NUM表示进程数量,NUM=0时表示使用所有CPU核心。
pm2 start myapp.js --watch --->当应用程序中的文件发生变化时,自动重启应用。 pm2 delete pid/app_name --->删除指定进程,pm2 delete all表示删除所有进程。
除了支持常规命令启动外,pm2还支持执行JSON文件启动。用法如下: pm2 start myPM2.json
在myPM2.json文件中,需要指定项目所在路径、项目启动脚本等信息。
pm2官网:http://pm2.keymetrics.io/
16. gulp
用于构建NodeJS项目,是一个非常轻巧的工具工具,而且学习成本低。 如何使用?
1. 全局安装gulp模块 cnpm install -g gulp
2. 进入项目所在目录,执行如下命令: npm install gulp --save-dev
这里是为了在项目中能使用gulp提供的插件,所以需要在项目中再安装一次gulp模块。
3. 在当前目录下创建gulpfile.js,内容如下: var gulp = require('gulp'); gulp.task('default', function(){
console.log('default taks callback...'); });
至此,一个最基本的gulp任务脚本就创建完毕。 4. 执行gulp任务脚本,命令如下: gulp TASK_NAME
在webstorm中:直接右击gulpfile.js ---> show Gulp tasks,可以看到如下界面:
双击任何一个任务节点即可执行任务。 gulp常用APIs
gulp为我们提供了四个常用API: task
格式:gulp.task(TASK_NAME, [DEPENDENCY_TASK], function(){})
描述:创建一个gulp任务。
watch
格式:gulp.watch(FILE_PATH, [TASK_NAME])
描述:监视文件的变化并运行相应的任务。
src
格式:gulp.src(FILE_PATH, [TASK_NAME])
描述:指明需要处理的文件的路径。
dest
格式:gulp.dest(FILE_PATH)
描述:指明任务处理后目标输出路径。
完整示例:
因篇幅问题不能全部显示,请点此查看更多更全内容