您的位置:首页 > Web前端 > Node.js

Node js 探讨之 初识node

2015-12-12 16:43 507 查看
前言:工作之余,在周末利用闲暇的时间探讨下node.js技术,充实自己的硬实力,扩充视野!

参考来源:http://www.runoob.com/nodejs/nodejs-http-server.html

说明:主要目的是记录自己的成长之路.多年以后再回首时能会想起当初的奋斗之路!

一 创建第一个应用

仍然是参考教程,这里整理了下步骤:(window版)

1.去node.js的官网下载 window版的Node,js http://nodejs.cn/

2.安装完毕后

(1)打开window cmd命令行,输入 node --version(能正常输出版本号)

(2)打开node.exe,输入 console.log('Hello!');(能正常输出)

3.在硬盘其它地方,创建一个测试项目文件夹,里面创建testServer.js,内容如下:

var http = require('http');

http.createServer(function(request,response){
	
	//发送 HTTP头部
	//Http状态值 200代表ok
	//内容类型,头部是 text,文本类型
	response.writeHead(200,{'Content-Type':'text/plain'});
	//发送响应数据
	response.end('Hello Word\n');
	
}).listen(8888);

//终端打印信息,node.js是单线程的,所以执行listen成功之后才执行这个输出
console.log('Server running at http://127.0.0.1:8888');[/code]4.打开cmd命令行(注意,这里不是node.exe-因为node.exe是node的交互解释器) 
然后进入创建的项目目录,(我这里为:D:\programing\NodeJS\project\test001),

然后运行 (node testServer.js)

最终控制台正常输出打印信息

5.打开浏览器,输入(http://127.0.0.1:8888/)-服务监听的端口以及地址

可以正常显示打印信息

至此,第一个Node.js 应用就已经创建并运行完毕!

二 NPM使用

由于现在的node.js安装时已经集成NPM,所以并不需要像以前一样那么复杂的安装了.

1.只需要 在cmd中输入(npm -v)就可以看到当前的npm版本了.

2.npm常见命令:

NPM提供了很多命令,例如install和publish,使用npm help可查看所有命令。
使用npm help <command>可查看某条命令的详细帮助,例如npm help install。
在package.json所在目录下使用npm install . -g可先在本地安装当前命令行程序,可用于发布前的本地测试。
使用npm update <package>可以把当前目录下node_modules子目录里边的对应模块更新至最新版本。
使用npm update <package> -g可以把全局安装的对应命令行程序更新至最新版。
使用npm cache clear可以清空NPM本地缓存,用于对付使用相同版本号发布新版本代码的人。
使用npm unpublish <package>@<version>可以撤销发布自己发布过的某个版本代码。


3.在命令行中通过npm下载express模块

注意: 将安装包放在 ./node_modules 下(运行 npm
命令时所在的目录
),如果没有 node_modules 目录,会在当前执行 npm 命令的目录下生成 node_modules 目录

比如:在 D:programing\NodeJS\project\test001 中运行 npm install express 就是将express模块安装到这个文件夹中

4.安装完毕express模块后(其实也顺带安装了一些其它模块),可以通过 npm ls 查看已安装的模块

注意:目前采用的是本地安装(因为可以被requires引用)

三 Node.js REPL(交互解释器-Read-Eval-Print-Loop)

说明:类似于windows的cmd终端和linux的shell终端,Node.js也有自己的终端,可以识别用户的输入,并执行任务.

1.直接在node.js的安装目录打开node.exe即可打开终端

2.在cmd中 输入 node 也可进入node的终端

3.连续按 两次 ctrl+c 即可退出终端

4.在终端中可以写自己的逻辑代码,并且能在控制台输出

5.一些常用命令

ctrl + c - 退出当前终端。
ctrl + c 按下两次 - 退出 Node REPL。
ctrl + d - 退出 Node REPL.
向上/向下 键 - 查看输入的历史命令
tab 键 - 列出当前命令
.help - 列出使用命令
.break - 退出多行表达式
.clear - 退出多行表达式
.save filename - 保存当前的 Node REPL 会话到指定文件
.load filename - 载入当前 Node REPL 会话的文件内容。


具体参考:http://www.runoob.com/nodejs/nodejs-repl.html

四 Node.js 的处理机制

node.js是单线程(这个单线程是指开发过程中开发人员使用的是单线程,而底层的实现仍然是多线程-将耗时的操作代理给了操作系统或多线程)

1.通过回调方法来处理异步事件.下面是异步模型大致过程(地址:http://segmentfault.com/q/1010000000190024)

其实现在的异步模型大同小异,大致过程如下(分三层):

(1).(最重要的)维护一个事件反应堆,用epoll或者select或者kqueue来做,反应堆的作用就是用同步的方式处理异步问题,在反应堆上注册好事件后如果相应的事件发生,就调用其回调函数,一般情况下反应堆是一个进程内全局唯一的。

<pre name="code" class="javascript">(2)<span style="font-family: Arial, Helvetica, sans-serif;">.上层的buffer,维护一系列的buffer用于管理每一个连接的数据,可以把buffer看做是一个对象。一般在一个连接到达的时候分配一个buffer对象,然后上层的连接注册事件的时候是注册到buffer上,buffer再注册到反应堆中。</span>
(3)<span style="font-family: Arial, Helvetica, sans-serif;">.就是一个个的连接对象,把每一个来自外部的连接都抽象为一个具体的对象,用于管理每一个连接,其中这个对象就包含了上面所说的buffer对象和其他一些状态。</span>
处理并发的过程就是这样的:
(1)<span style="font-family: Arial, Helvetica, sans-serif;">.为监听套接口在反应堆注册一个事件,此事件发生调用对应的回调,一般情况是accept这个连接,然后为这个连接创建连接对象,统一管理。</span>
(2)<span style="font-family: Arial, Helvetica, sans-serif;">.为此连接创建buffer对象,并注册对应的读写错误事件的回调(上层对于buffer的读写事件回调都是业务层来控制的了).</span>
(3)<span style="font-family: Arial, Helvetica, sans-serif;">.(所谓的排队机制也不是完全正确)在加入监听队列后是离散的,准确来说epoll中是由一颗红黑树维护的,每一个事件的先后顺序跟它达到的顺序有关。</span>
(4)<span style="font-family: Arial, Helvetica, sans-serif;">.维护了众多的连接对象,也就是这里的并发情况了,如果有事件发生会调用回调来处理,理论上无阻塞情况减少了很多CPU的wait,这部分时间用于处理真正的业务,所以异步模型能够带来很高的CPU处理能力,减少等待,单位时间处理的事件越多,从外部来看并发就很高,实际上也是一个串行的工作状态,但是串行过程没有等待。</span>



2.node.js中使用事件驱动模型,核心是(events.EventEmitter-一些重要的API的实现都是继承自这个得,比如fs,http)

五 Node.js Buffer(缓冲区)

js本身只有字符串数据类型,没有二进制数据类型

但是在处理像Tcp流或文件流时,必须使用到二进制数据.因此,在node.js中,定义了一个buffer类,该类用来创建一个专门存放二进制数据的缓存区.

(在 Node.js 中,Buffer 类是随 Node 内核一起发布的核心库。Buffer 库为 Node.js 带来了一种存储原始数据的方法,可以让 Node.js 处理二进制数据,每当需要在 Node.js 中处理I/O操作中移动的数据时,就有可能使用 Buffer 库。原始数据存储在 Buffer 类的实例中。一个 Buffer 类似于一个整数数组,但它对应于 V8 堆内存之外的一块原始内存

-来源:http://www.runoob.com/nodejs/nodejs-buffer.html)

六 Node.js Stream(流)Stream 是一个抽象接口,Node 中有很多对象实现了这个接口。例如,对http 服务器发起请求的request 对象就是一个 Stream,还有stdout(标准输出)。

Node.js,Stream 有四种流类型:
Readable - 可读操作。
Writable - 可写操作。
Duplex - 可读可写操作.
Transform - 操作被写入数据,然后读出结果。
所有的 Stream 对象都是 EventEmitter 的实例。常用的事件有:
data - 当有数据可读时触发。
end - 没有更多的数据可读时触发。
error - 在接收和写入过程中发生错误时触发。
finish - 所有数据已被写入到底层系统时触发。


通过操作流,可以轻易实现各种文件之间的转换,压缩等操作

七 Node.js模块系统

为了让Node.js的文件可以相互调用,Node.js提供了一个简单的模块系统。

模块是Node.js 应用程序的基本组成部分,文件和模块是一一对应的。换言之,一个 Node.js 文件就是一个模块,这个文件可能是JavaScript 代码、JSON 或者编译过的C/C++ 扩展(http://www.runoob.com/nodejs/nodejs-module-system.html)

1.Node.js 中通过 require(模块名)引入相应模块

2.各个模块(原生模块和本地模块)之间的引入优先级如图

3.require获取对应模块后,只会获取该模块的exports对象,所以需要把提供给外部调用的方法写入exports对象中(如exports.test=***)

4.也可以通过(module.exports = 对象)来指定本模块的特定导出对象

八 Node.js路由

示例:

1.router.js

/* 
 * @description自定义路由构造函数
 */
function RouteCustom(){
	
};
/*
 * @description扩展原型 
 */
RouteCustom.prototype.route =function(pathName){
	console.log("About to route a request for "+pathName);
};
//将导出模块指定为路由
module.exports = new RouteCustom();
2.server.js

//引入http模块
var http = require("http");
//引入url模块
var url = require("url");

/*
 * @description 自定义服务器构造函数 
 */
 function Server(){
	 console.log("create a new server");
 };
 /*
 * @description扩展原型 
 */
Server.prototype.start =function(route){
	function onRequest(request, response) {
		var pathname = url.parse(request.url).pathname;
		console.log("Request for " + pathname + " received.");
		if(route&&typeof(route)=='function'){
			route(pathname);
		}	
		
		response.writeHead(200, {"Content-Type": "text/plain"});
		response.write("Hello World");
		response.end();
  }

  http.createServer(onRequest).listen(8888);
  console.log("Server has started.");
};
 //将导出模块指定为自定义服务器
module.exports = new Server();


3.main.js

var server = require("./server.js");
var router = require("./router.js");

server.start(router.route);
4.cmd进入项目文件夹 然后执行(node main.js)

就已经开启了服务了,绑定了8888端口,然后接受到网络请求时,就会打印出来



代表路由里面已经接收到了服务器传过去的参数,现在测试版只是默认传入path,

也可以换位 请求参数,其它的.

(相当于每一次服务器的请求都会转交有效消息给路由)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: