Nodejs的非阻塞IO、异步以及 事件驱动EventEmitter解决异步 (7)
1、 Nodejs 的单线程 非阻塞 I/O 事件驱动
Node.js 不为每个客户连接创建一个新的线程, 而仅仅使用一个线程。当有用户连接了,
就触发一个内部事件,通过非阻塞 I/O、事件驱动机制,让 Node.js 程序宏观上也是并行的。
使用 Node.js,一个 8GB 内存的服务器,可以同时处理超过 4 万用户的连接。
2 异步IO执行过程
console.log('1'); // fs.readFile 是非阻塞IO fs.readFile('mime.js',function (err,data) { console.log('2'); }); console.log('3');
执行结果
2、 异步存在的问题
// 错误写法 // 非阻塞io 引发的问题 function getMime() { console.log('1'); // 1 fs.readFile('mime.json',function(err,data){ console.log('2'); // 2 return data.toString(); }); console.log('3'); // 3 } console.log(getMime()); // undefined
执行结果,获取不到文件内容
3 回调解决异步问题
// 正确写法 var fs = require('fs'); // 回调 callback function getMime(callback) { fs.readFile('mime.json',function(err,data){ callback(data); //使用回调传值 }); } getMime(function (result) { console.log(result.toString()); // 回调过程中获取值 }); // 执行函数
4 事件驱动
1. nodejs 事件循环:
nodejs 是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高;
nodejs 的每一份api都是异步的,并作为一个独立线程运行,使用一步函数调用,并处理并发;
nodejs 有多个内置的事件,我们可以通过引入 events 模块,并实例化 EventEmitter 类来绑定和监听事件.
// 引入 events 模块 var events=require('events'); //console.log(events); // 实例 EventEmitter 监听和广播 事件对象 var EventEmitter=new events.EventEmitter(); //广播 和接收广播 EventEmitter.on('to_mime',function(data){ console.log(data); }); //监听to_parent的广播 EventEmitter.on('to_parent',function(data){ //console.log('接收到了这个广播事件'); console.log(data); EventEmitter.emit('to_mime','给mime发送的数据') }); setTimeout(function(){ console.log('开始广播...'); //广播to_parent事件 EventEmitter.emit('to_parent','给to_parent发送的数据') },1000);
执行结果
5 使用事件驱动解决异步问题
var fs = require('fs'); var events = require('events'); var EventEmitter = new events.EventEmitter(); function getMime() { fs.readFile('mime.json',function(err,data){ EventEmitter.emit('mime',data) // 事件传值 }); } getMime(); //执行函数 // 监听 mime 事件 EventEmitter.on('mime',function (data) { console.log(data.toString()); });
6 get 和post 请求
//引入http模块 var http=require('http'); var url=require('url'); var ejs=require('ejs'); var fs=require('fs'); //路由:指的就是针对不同请求的 URL,处理不同的业务逻辑。 http.createServer(function(req,res){ res.writeHead(200,{"Content-Type":"text/html;charset='utf-8'"}); //获取get 还是post请求 var method=req.method.toLowerCase(); //console.log(method); var pathname=url.parse(req.url,true).pathname; if(pathname==='/login'){ /*显示登录页面*/ ejs.renderFile('views/form.ejs',{ },function(err,data){ res.end(data); })}else if(pathname==='/dologin' &&method==='get'){ //get获取数据 console.log(url.parse(req.url,true).query); res.end('dologin'); }else if(pathname==='/dologin' &&method==='post'){ //post获取数据 var postStr =''; req.on('data',function (chunk) { postStr +=chunk; }); req.on('end',function (err,chunk) { console.log(postStr); fs.appendFile('login.txt',postStr +'\n',function (err) { if (err){ console.log(err); } console.log('写入文件成功'); }) }) }else{ res.end('other') } }).listen(8001);