一、node.js是什么
特点:
1. 单线程
2. 异步
3. 事件驱动
(①异步:让出CPU使用权,完成后,再夺回CPU控制权。
②事件驱动:
【第一个例子是关于医生看病】
在美国去看医生,需要填写大量表格,比如保险、个人信息之类,传统的基于线程的系统(thread-based system),接待员叫到你,你需要在前台填写完成这些表格,你站着填单,而接待员坐着看你填单。你让接待员没办法接待下一个客户,除非完成你的业务。
想让这个系统能运行的快一些,只有多加几个接待员,人力成本需要增加不少。
基于事件的系统(event-based system)中,当你到窗口发现需要填写一些额外的表格而不仅仅是挂个号,接待员把表格和笔给你,告诉你可以找个座位填写,填完了以后再回去找他。你回去坐着填表,而接待员开始接待下一个客户。你没有阻塞接待员的服务。
你填完表格,返回队伍中,等接待员接待完现在的客户,你把表格递给他。如果有什么问题或者需要填写额外的表格,他给你一份新的,然后重复这个过程。
这个系统已经非常高效了,几乎大部分医生都是这么做的。如果等待的人太多,可以加入额外的接待员进行服务,但是肯定要比基于线程模式的少得多。
【第二个例子是快餐店点餐】
在基于线程的方式中(thread-based way)你到了柜台前,把你的点餐单给收银员或者给收银员直接点餐,然后等在那直到你要的食物准备好给你。收银员不能接待下一个人,除非你拿到食物离开。想接待更多的客户,容易!加更多的收银员!
当然,我们知道快餐店其实不是这样工作的。他们其实就是基于事件驱动方式,这样收银员更高效。只要你把点餐单给收银员,某个人已经开始准备你的食物,而同时收银员在进行收款,当你付完钱,你就站在一边而收银员已经开始接待下一个客户。在一些餐馆,甚至会给你一个号码,如果你的食物准备好了,就呼叫你的号码让你去柜台取。关键的一点是,你没有阻塞下一个客户的订餐请求。你订餐的食物做好的事件会导致某个人做某个动作(某个服务员喊你的订单号码,你听到你的号码被喊到去取食物),在编程领域,我们称这个为回调(callback function)。
)
优点:快
缺点:消耗内存
二、node.js VS PHP
优点:
1. 性能高
2. 开发效率高
3. 应用范围广(可以开发桌面系统electron框架)
缺点:
1.新,人少
2.中间件少
3.IDE不完善
三、框架选择
比较热门的:express koa hapi,已经express基础上的sails。
四、例子
例一:
var http = require('http'); //http node.js自带对象
http.createServer(function (request, response) {
response.writeHead(200, {'Content-Type': 'text/html; charset=utf-8'});
if(request.url!=="/favicon.ico"){ //清除第2此访问 node.js bug,第二次访问/favicon.ico
console.log('request'); //如果没有上一行,访问一次,输出两次‘request’
response.write('hello,world');
response.end('');//不写则没有http协议尾,但写了会产生两次访问
}
}).listen(8000);
console.log('Server running at http://127.0.0.1:8000/');
/*
启动服务
cmd下执行:
node n1_hello.js
浏览器访问:http://localhost:8000
*/
例二、调用函数
var http = require('http');
var otherfun = require('./modules/fun2.js');
http.createServer(function (request, response) {
response.writeHead(200, {'Content-Type': 'text/html; charset=utf-8'});
if(request.url!=="/favicon.ico"){ //清除第2此访问
fun1(response);
otherfun.fun2(response); //也可以这样写 otherfun['fun2'](response);
otherfun.fun3(response);
response.end('');
}
}).listen(8000);
console.log('Server running at http://127.0.0.1:8000/');
//---普通函数
function fun1(res){
res.write("你好,我是fun1");
}
//module.exports = fun2; //只支持一个函数
//支持多个函数
module.exports={
fun2:function(res){
res.write("hello , fun2!");
},
fun3:function(res){
res.write("hello , fun3!");
}
}
/*function fun2(res){
console.log("fun2");
res.write("hello , fun2!");
}*/
例三、调用模块
var http=require('http');
//var User = require('./models/User');
var Teacher = require('./models/Teacher');
http.createServer(function (request,response){
response.writeHead(200,{'Content-Type':'text/html;charset=utf-8'});
if(request.url!=="/favicon.ico"){ //清除第2此访问
teacher = new Teacher(1,'李四',30);
teacher.teach(response);
response.end('');
}
}).listen(8000);
console.log('Server running at http://127.0.0.1:8000/');
//--------------User.js--------------
function User(id,name,age){
this.id=id;
this.name=name;
this.age=age;
this.enter=function(){
console.log("进入图书馆");
}
}
module.exports = User;
//-------------------models/Teacher.js---------
var User = require('./User');
function Teacher(id,name,age){
User.apply(this,[id,name,age]);
this.teach=function(res){
res.write(this.name+"老师讲课");
}
}
module.exports = Teacher;
例三、路由初步
var http = require('http');
var url = require('url');
var router = require('./router');
http.createServer(function (request, response) {
response.writeHead(200, {'Content-Type': 'text/html; charset=utf-8'});
if(request.url!=="/favicon.ico"){
var pathname = url.parse(request.url).pathname;
//console.log(pathname);
pathname = pathname.replace(/\//, '');//替换掉前面的/
//console.log(pathname);
router[pathname](request,response);
response.end('');
}
}).listen(8000);
console.log('Server running at http://127.0.0.1:8000/');
//-----------------router.js--------------------------------
module.exports={
login:function(req,res){
res.write("我是login方法");
},
zhuce:function(req,res){
res.write("我是注册方法");
}
}
例五、读取文件
var http = require('http');
var optfile = require('./models/optfile');
http.createServer(function (request, response) {
response.writeHead(200, {'Content-Type': 'text/html; charset=utf-8'});
if(request.url!=="/favicon.ico"){ //清除第2此访问
console.log('访问');
response.write('hello,world');
//optfile.readfile("G:\\www\\nodejs\\one\\models\\aa.txt");
optfile.readfileSync("G:\\www\\nodejs\\one\\models\\aa.txt");
response.end('hell,世界');//不写则没有http协议尾
}
}).listen(8000);
console.log('Server running at http://127.0.0.1:8000/');
//-------------optfile.js-------------------------
var fs= require('fs');
module.exports={
readfile:function(path){ //异步执行
fs.readFile(path, function (err, data) {
if (err) {
console.log(err);
}else{
console.log(data.toString());
}
});
console.log("异步方法执行完毕");
},
readfileSync:function(path){ //同步读取
var data = fs.readFileSync(path,'utf-8');
//console.log(data);
console.log("同步方法执行完毕");
return data;
}
}
例六、写文件
var fs= require('fs');
module.exports={
writefile:function(path,data){ //异步方式
fs.writeFile(path, data, function (err) {
if (err) {
throw err;
}
console.log('It\'s saved!'); //文件被保存
});
},
writeFileSync:function(path,data){ //同步方式
fs.writeFileSync(path, data);
console.log("同步写文件完成");
}
}
例七、读取图片
var http = require('http');
var optfile = require('./models/optfile');
http.createServer(function (request, response) {
//response.writeHead(200, {'Content-Type': 'text/html; charset=utf-8'});
response.writeHead(200, {'Content-Type':'image/jpeg'});
if(request.url!=="/favicon.ico"){ //清除第2此访问
console.log('访问');
//response.write('hello,world');//不能向客户端输出任何字节
optfile.readImg('./imgs/pig.png',response);
//------------------------------------------------
console.log("继续执行");
//response.end('hell,世界');//end在方法中写过
}
}).listen(8000);
console.log('Server running at http://127.0.0.1:8000/');
//---------------------optfile.js--------------------------------
var fs= require('fs');
module.exports={
readImg:function(path,res){
fs.readFile(path,'binary',function(err, file) {
if (err) {
console.log(err);
return;
}else{
console.log("输出文件");
//res.writeHead(200, {'Content-Type':'image/jpeg'});
res.write(file,'binary');
res.end();
}
});
}
};