NODEJS进阶 | 8月更文挑战

211 阅读7分钟

1,事件循环机制

Node.js 在什么时候会进入事件循环呢?答案是 Node.js 程序由事件循环开始,到事件循

环结束,所有的逻辑都是事件的回调函数,所以 Node.js 始终在事件循环中,程序入口就是

事件循环第一个事件的回调函数。事件的回调函数在执行的过程中,可能会发出 I/O 请求或

直接发射(emit)事件,执行完毕后再返回事件循环,事件循环会检查事件队列中有没有未

处理的事件,直到程序结束。

2,事件

Node.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列。在开发者看来,事

件由 EventEmitter  对象提供。前面提到的 fs.readFile  和  http.createServer 的回

调函数都是通过  EventEmitter  来实现的。 下面我们用一个简单的例子说明  EventEmitter

的用法:

var EventEmitter = require('events').EventEmitter;

var event = new EventEmitter();

event.on('some_event'function() {     //事件的注册:event.on(“事件名称”,回调函数)

console.log('some_event occured.');

});

setTimeout(function() {

event.emit('some_event');                       //事件的触发:event.emit('事件名称');

}, 1000);

运行这段代码,1秒后控制台输出了 some_event occured. 。 其原理是  event  对象注册了事件  some_event  的一个监听器,然后我们通过  setTimeout  在1000毫秒以后向

event  对象发送事件  some_event ,此时会调用 some_event 的监听器。

3,node的工作原理

clipboard.png

一开始的请求可能是I/o请求,网络通信请求,数据库查询请求,都是一个请求事件,都会进入node的事件循环机制里面,事件循环发现对应的请求以后就会调用相应的回调函数,

回调函数处理完之后,又会回到事件循环机制里面,查看还有没有其它的事件请求

4, package原理

Node.js 在调用某个包时,会首先检查包中 package.json 文件的 main  字段,将其作为

包的接口模块,如果 package.json 或 main 字段不存在,会尝试寻找 index.js 或 index.node 作

为包的接口。

clipboard2.png

5, node.js工具

(1) node.js 的全局变量:global      

global.A="1111";

Node.js常用工具

1:util    util是node.js的核心模块,提供常用的函数集合,用于 弥补核心JavaScript的功能过于精简的不足

util.inherits(constructor,superConstructor)    是一个实现对象间圆形继承的函数
util.inspect(object,xxx)  是一个将任意对象转换为字符串的方法
util.isArray(object)    如果给定的参数object是一个数组还回true,否则返回false    ,下面同理
util.jsRegExp(object)
util.isDate(object); 
uitl.isError(object)

2: fs模块封装的是文件系统,它提供了文件的读取,写入,更名,删除,遍历目录,链接等

读取文件内容函数:异步方法:fs.readFile()
同步方法:fs.readFileSync()

3 :  fs.open(path,flags,xxx) 

4:  fs.read(fd,buffer,offset,length,position,xxx) 5: 常用的工具类:util和事件EventEmitter util.inherits(constructor , superConstructor) util.inherits(Sub,Base);//让Sub继承Base接口,这样Sub就有Base的扩展属性了

var util=require('util');
function Base() {
    this.name='base';
    this.base=2012;
    this.sayHello=function(){
        console.log('hello'+this.name+'this year is '+this.base);
    };
}
Base.prototype.showName=function(){
    console.log(this.name);
}
function Sub(){
    this.name='sub';
}

//原型继承

util.inherits(Sub,Base);//让Sub继承Base接口,这样Sub就有Base的扩展属性了
var objBase=new Base();
    objBase.showName();
    objBase.sayHello();
    console.log(objBase);
    objSub.showName();
    console.log(objSub);

6: util inspect(object);

此方法是一个将任意对象转换成字符串的方法

7:events是node.js最重要的模板

evetns.EventEmitter,EventEmitter的核心就是事件发射与时间监听器功能的封装

//首先引入工具类

var events=require('events');

//实例化事件对象

var emitter=new events.EventEmitter();

//注册事件监听器1

emitter.on('someEvent'function (arg1, arg2) {
    console.log('listener1',arg1,arg2);
});

//注册事件监听器2

emitter.on('someEvent'function (arg1, arg2) {
    console.log('listener2',arg1,arg2);
});

//触发事件

emitter.emit('someEvent','zlm1323',1991);
emitter.once();//注册一个单次监听器
removeListener()

8:error事件

EventEmitter定义了一个特殊的事件error

9: fs模块 是文件操作的封装,它提供了文件的读取,写入,更名,删除,遍历目录。与其他模块不同的是fs模块中所 有的操作都提供了 异步和同步两个版本:读取文件类容: 异步方法:readFile()      同步方法:readFileSync();

10: http模块

//引入模块

var http=require('http');

//创建服务

var server=http.createServer(function(req,res){

    //响应头

    res.writeHead(200,{'Content-Type':'text/plain'});

    //响应内容

    res.write('<h1>Node.js</h1>h1>');

    //响应结束

    res.end('Hello World\n');

});

server.listen(1888);

console.log("Server Running at 8888")

http:提供了三个事件用于控制请求体传输 serverRequest

(1):data,当请求体数据到来时,该事件被触发,改事件一共一个参数chunk,表示接受到的参数

 (2):end,当请求体数据传输完成时,该事件被触发,以后将不会再有数据到来

  (3):close,用户当前请求结束时,该事件被触发,不用于end,如果用户强制终止了传输,也会触发close

11: 请求

Node.js 的异步编程接口习惯是以函数的最后一个参数为回调函数,通

常一个函数只有一个回调函数。回调函数是实际参数中第一个是  err ,其

余的参数是其他返回的内容。如果没有发生错误, err 的值会是  null 或

undefined 。如果有错误发生, err 通常是  Error 对象的实例。

get请求:

var http = require('http');

var url = require('url');

var util = require('util');

http.createServer(function(req, res) {

res.writeHead(200, {'Content-Type': 'text/plain'});

res.end(util.inspect(url.parse(req.url, true)));

}).listen(3000);


post请求:

var http = require('http');

var querystring = require('querystring');

var util = require('util');

http.createServer(function(req, res) {

var post = '';

req.on('data', function(chunk) {

post += chunk;

});

req.on('end', function() {

post = querystring.parse(post);

res.end(util.inspect(post));

});

}).listen(3000);

上面代码并没有在请求响应函数中向客户端返回信息,而是定义了一个  post 变量,用

于在闭包中暂存请求体的信息。 通过  req 的  data 事件监听函数, 每当接受到请求体的数据,

就累加到  post 变量中。在  end 事件触发后,通过 querystring.parse 将  post 解析为

真正的 POST 请求格式,然后向客户端返回。

6, Http客服端

http  模块提供了两个函数  http.request  和  http.get ,功能是作为客户端向 HTTP

服务器发起请求。

http.request(options, callback) 发起 HTTP 请求

http.get(options, callback) http  模块还提供了一个更加简便的方法用于处

理GET请求: http.get 。 它是  http.request 的简化版, 唯一的区别在于 http.get

自动将请求方法设为了 GET 请求,同时不需要手动调用 req.end() 。

http.ClientRequest  是由  http.request 或  http.get 返回产生的对象,表示一

个已经产生而且正在进行中的 HTTP 请求。

7, node.js调试方法:

node的第一种调试技巧:1:进入需要调试的js脚本文件所在目录

                   2:cmd窗口     node --debug-brk=5858 test.js

                   3:重新打开另一个cmd窗口: node-inspector

                   4:最后chorme浏览器中输入:

                    http://127.0.0.1:8080/?ws=127.0.0.1:8080&port=5858

8, 总结

1:导出模块  exports

nodejs里面有个特殊的变量:module,它代表当前模块自身,而module.exports是模块对外导出的对象,

它可以是任何对象,

2 : 加载模块  require函数可以加载某个模块

3:模块大约分为几种类型:核心模块 , 本地模块 , 和通过NPM安装的第三方模块

4:根据模块的类型,可以分为几种不同的引用方式:

    (1):核心模块不能通过路径来引用,只能用模块名加载,核心模块有最高的加载优秀级,即使已经有了

                      一个同名的第三方模块,核心模块也会被优先加载

                      如: var http=require('http');

     (2):也可以使用绝对路径从文件系统里加载模块

                  var  myModule=require('/home/pedro/my_modules/my_module')

                  如果是基于当前文件路径

                   var  myModule2=require('./lib/my_module_2')

     (3):加载目录模块 也可以使用目录的路径来加载模块

                     var myModule=require('./myModuleDir')

    (4):从node_modules目录加载 ,如果require函数的参数不是相对路径,也不是核心模块

                        名,node会载当前目录的node_modules子目录下查找

                        如:var myModule=require('myModule.js')

小结

Node取消了JavaScript的默认全局作用域,转而采用CommonJS模块系统,这样你可以更好的组织你的代码,也因此避免了很多安全问题和bug。可以使用require函数来加载核心模块,第三方模块,或从文件及目录加载你自己的模块

还可以用相对路径或者绝对路径来加载非核心模块,如果把模块放到了node_modules目录下或者对于用NPM安装的模块,你还可以直接使用模块名来加载。