NodeJS异步实现
Node.js异步编程的直接体现就是回调,它依托于回调来实现,但不能说使用了回调他就是异步了
回调函数在完成任务后就会被调用,Node使用了大量的回调函数,Node所有的API都支持回调函数
例如:我们可以一边读取文件一边执行其他命令,在文件读取完成后,我们将文件内容作为回调的参数返回,这样执行代码的时候就不会有阻塞或等待I/O操作
这样就打打提高了Node.js性能,可以处理大量的并发请求。
一、阻塞代码示例
1、创建一个测试文件text.txt文件内容如下:
文件I/O操作:open the file ==>帅哥很帅
创建index.js文件
#!/usr/bin/env node var fs = require("fs"); var data = fs.readFileSync('test.txt'); console.log(data.toString()); console.log('帅哥执行命令测试~~~');
2、执行结果
LuoTimdeMacBook-Pro-2:bin luotim$ node index.js 文件I/O操作:open the file ==>帅哥很帅 帅哥执行命令测试~~~
从结果上可以看出来先进行了I/O操作才执行的输出命令
二、非阻塞代码的实现
修改代码
#!/usr/bin/env node var fs = require("fs"); fs.readFile('test.txt',function (error,data) { if (error) return console.error(error); console.log(data.toString()); }); console.log("异步程序测试~~");
2、执行结果
LuoTimdeMacBook-Pro-2:bin luotim$ node index.js 异步程序测试~~ 文件I/O操作:open the file ==>帅哥很帅
从结果上就可以看出第一个程序在文件读取完后才执行完程序,第二个实例我们不需要等待文件读取完这样就可以在读取文件的同时执行后续的代码,大大提高了程序性能。
对于Nodejs来说阻塞是按顺序执行的,而非阻塞不需要按照顺序执行直接把相关的I/O操作交给回调函数执行。
Node.js事件循环
Nodejs是单进程和单线程应用程序,但是通过事件和回调支持并发(看上面异步实现),所以性能非常高。
并且Nodejs的每一个API都是异步的,并作为独立的一个线程运行,使用异步函数调用,并处理并发!
Nodejs基本上所有的事件机制都是使用设计模式中“观察者模式”实现
#观察者模式 观察者模式(有时又被称为发布(publish )-订阅(Subscribe)模式、模型-视图(View)模式、源-收听者(Listener)模式或从属者模式)是软件设计模式的一种。 在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。 这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。
Node.js单线程类似进入一个while(true)的事件循环,知道没有事件观察者退出,每个异步事件都生成一个事件观察者,如果没有事件发生就调用该回调函数。
事件驱动程序
Node.js使用事件驱动模型,当web server接收到请求,就把他关闭然后进行处理,然后去服务下一个web请求。
当这个请求完成,它被放回处理队列中,当到达队列开头,这个结构就返回给用户。
因为webserver一直接受请求不等待任何的I/O读写操作(非阻塞I/O或者事件驱动I/O)
整个的驱动流程就是如上图这样实现的,非常简洁.
二、通过events模块来绑定和触发事件
1、导入模块并实例化对象
//引入events模块 var events = require("events"); //创建evenEmitter对象 var evenEmitter = new events.EventEmitter();
2、绑定定事件处理程序,当事件触发后执行的程序
//绑定事件及事件的处理程序 evenEmitter.on('evenName',eventHandler);
3、可以通过程序来触发
//我们可以通过程序触发事件 evenEmitter.emit('evenName');
实例:
#!/usr/bin/env node //引入events模块 var events = require("events"); //创建evenEmitter对象 var eventEmitter = new events.EventEmitter(); // 创建事件处理程序 var connectHandler = function connected() { console.log('连接成功。'); // 触发 data_received 事件 eventEmitter.emit('data_received'); }; // 绑定 connection 事件处理程序 eventEmitter.on('connection', connectHandler); // 使用匿名函数绑定 data_received 事件 eventEmitter.on('data_received', function(){ console.log('数据接收成功。'); }); // 触发 connection 事件 eventEmitter.emit('connection'); console.log("程序执行完毕。");
梳理流程图:(用于梳理)事件的绑定执行