Nodejs结构和创建

本文参考自《Node.js开发指南》和《Node.js实战》两本书。

异步I/0

Node.js最大的特点就是采用了异步I/0与事件驱动的架构设计。

1
2
3
$.post('/resource.json', function(data){
console.log(data);
})

这一小段代码是jQuery中的Ajax请求,我们知道这个结果函数是异步的,等服务器响应结果后才会执行。

对于一些高并发的需求,传统的解决方法是多线程模型,每个业务提供一个线程系统,通过切换和调度线程来实现高并发中的等待开销。但是这样做无疑又增加了线程管理和调度的开销。

Nodejs采用的是单线程模型,对于所有的I/O操作(阻塞操作)都采用类似上面Ajax请求的异步的请求方式,避免了频繁切换线程。

Nodejs的异步机制是基于事件的,所有的磁盘I/0、网络通讯、数据库查询都以非阻塞方式请求,返回的结果由事件循环来处理。Nodejs进程在同一时刻只会处理一个事件,完成后立即进入事件循环检查并处理后面的事件。这样做的好处是,CPU和内存在同一时间集中处理一件事,同时尽可能让耗时的I/0操作并行执行。

Node.js架构

Node.js用异步式I/0和事件驱动代替多线程,带来了客观的性能提升。Node.js除了用V8作为JavaScript引擎外,还使用了高效的libev和libeio库支持事件驱动和异步式I/0.

Node.js的开发者在libev和libeio的基础上抽象出了libuv.

Nodejs安装

Node.js的下载和安装请访问官网:https://nodejs.org/zh-cn/

因为我的系统是deepin的,所以下面是Ubuntn下的安装

1
2
sudo apt-get install nodejs
sudo apt-get install npm

npm是Node包管理器,是一个由Node.js官方提供的第三方包管理工具,就像PHP中的Pear、Python中的PyPI一样。npm是一个完全由JavaScript实现的命令行工具,通过Nodejs执行。

如果我们有需要安装多个版本的Node.js的需求,可以安装多版本管理器。n是一个十分简洁的Node多版本管理器,他的名字就一个字母。

1
npm install -g -n

安装完n后,可以使用n –help查看使用说明。详细可以访问n主页

Node.js Helloword

新建一个hw.js文件

1
console.log('hello word');

然后执行下面命令

1
node hw.js

这就是Node.js的helloword程序。

建立HTTP服务器

新建一个app.js的文件

1
2
3
4
5
6
7
8
9
var http = require('http');

http.createServer(function(req, res){
res.writeHead(200, {'Content-Type' : 'text/html'});
res.write('<h1>Node.js</h1>');
res.end('<p>Hello World</p>');
}).listen(3000);

console.log('HTTP server is listening at prot 3000.');

接下来运行node app.js命令,打开浏览器访问http://127.0.0.1:3000

用Node.js实现最简单的http服务器就这样诞生了。这个程序中调用了Node.js提供的http模块,对所有HTTP请求答复同样的内容并监听3000端口。

模块和包

模块(Module)和包(Package)是Node.js最重要的支柱。开发一个具有一定规模的程序不可能只用一个文件,通常需要把各个功能拆分、封装、然后组合起来。Node.js提供了require函数来调用其他模块,而且模块都是基于文件的,机制十分简单。

模块

在Node.js中模块和文件是一一对应的,一个Node.js文件就是一个模块,这个文件可能是JavaScript代码、JSON或者编译过的C/C++扩展。

上面我们使用var http = require(‘http’),其中http是Node.js的一个核心模块,其内部是用C++实现的,外部用JavaScript封装。

Node.js提供了exports和require两个对象,其中exports是模块公开的接口,require用于获取模块的接口。我们在同一个目录下创建两个文件

module.js

1
2
3
4
5
6
7
8
var name;
exports.setName = function(thyName){
name = thyName;
}

exports.sayHello = function(){
cosole.log('Hello ' + name);
}

getmodule.js

1
2
3
var myModule = require('./module');
myModule.setName('BYVoid');
myModule.sayHello();

运行node getmodule.js,结果是:

Hello BYVoid

创建包

包是在模块基础上更深一步的抽象,Node.js的包类似于C/C++的函数库或Java中的jar包。它将某个独立的功能封装起来,用于发布、更新、依赖管理和版本控制。

Node.js的包是一个目录,其中包含了一个JSON格式的包说明文件package.json.

Node.js在调用某个包时,会首先检查包中package.json文件的main字段,将其作为包的接口模块,如果package.json或main字段不存在,会尝试寻找index.js或index.node作为包的接口。