node.js
1.node是什么?
Node 是一个让 JavaScript 运行在服务端的开发平台, 发布于2009年5月,由Ryan Dahl开发,实质是对Chrome V8引擎进行了封装。Node对一些特殊用例进行优化,提供替代的API,使得V8在非浏览器环境下运行得更好。 Node用于方便地搭建响应速度快、易于扩展的网络应用。Node 使用事件驱动, 非阻塞I/O 模型而得以轻量和高效,非常适合在分布式设备上运行数据密集型的实时应用。
1) 什么是 V8?
V8 JavaScript 引擎是 Google 用于其 Chrome 浏览器的底层 JavaScript 引擎。实际上,JavaScript 引擎负责解释并执行代码。Google 使用 V8 创建了一个用 C++ 编写的超快解释器,该解释器拥有另一个独特特征;您可以下载该引擎并将其嵌入任何应用程序。V8 JavaScript 引擎并不仅限于在一个浏览器中运行。因此,Node 实际上会使用 Google 编写的 V8 JavaScript 引擎,并将其重建为可在服务器上使用。
3) 什么是并发?
一段时间内有多个程序在运行到运行完毕之间
4) 什么是进程?
一个软件运行过程中至少要有一个进程对应
5) 什么是线程?
线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务
多线程与单线程的效率问题:线程本身由于创建和切换的开销,采用多线程不会提高程序的执行速度,反而会降低速度,但是对于频繁IO操作的程序,多线程可以有效的并发.
6) 同步和异步有什么区别?
同步会阻塞: 循环 script加载src
异步不会阻塞代码: 定时器,link加载css,img加载src.
7) 什么是异步的IO.
要有数据的交互 异步的IO 读文件
没有数据的交互 异步的非IO setTimeout setInterval
var flag = 123; //假定条件
// 此处省略一万行
// 不能确定flag的值是否还为123,断言判断
console.assert(flag == 1234,'flag的值根本不等于123');
console.time('test');
for(var i = 0;i < 100000000;i++){
}
console.timeEnd('test');
3) 路径
console.log(__dirname); //当前文件所在的路径
console.log(__filename); //当前文件的全部路径
4.node.js中的内置模块
在node中,有一些内置的模块(包),通过require函数引入
内置模块:
- fs 文件系统;
- http 创建服务;
- path 路径;
- querystring 参数模块;
- url 地址栏;
- 自定义模块;
1.fs文件系统的模块:
1)读取文件
// fs 文件系统的模块
var fs = require("fs");
// console.log(fs);
// 异步读取文件
fs.readFile('./08.txt','utf8',function(err,data){ //如果编码格式不写,输出的就是一串buffer码
// console.log(err); //这是错误,但是没有抛出
if(err){
throw err; //把错误抛出来,有错误可以阻止代码继续往后面走
}
console.log(data)
})
// 同步
// var data = fs.readFileSync("./08.txt",'utf8') //同步读完就是函数的返回值
// console.log(data);
2)判断文件是否存在
//判断文件是否存在
fs.access('./08.txt',function(err){
if(err){
throw err;
}
// 如果没有抛出错误,文件存在
fs.readFile('./08.txt','utf8',function(err,data){
if(err) throw err;
console.log(data);
})
})
fs.access("./abc",function(err){ //可以判断文件夹
if(err){
throw err;
}
console.log('hello')
})
3)写文件
异步写文件 var obj = { "uname" : "admin", "upassword" : "admin" } var arr = []; // su shu arr.push(obj); var obj2 = { "uname" : "admin2", "upassword" : "admin2" } arr.push(obj2) var str = JSON.stringify(arr); fs.writeFile('./data/03.json',str,'utf8',function(err){ //如果写入成功,这个err为null // console.log(err); if(err){ throw err; //如果错误,将错误抛出 } console.log('文件写入成功') // 如果文件不存在,会帮你去创建对应的文件,但是不会创建文件夹 })
同步写文件
fs.writeFileSync(file, data[, options])
4)追加文件
异步的追加文件
fs.appendFile(path, data[, options], callback)
fs.appendFile("./data/04.json","hello world","utf8",function(err){
console.log(err);
console.log('OK')
})
同步的追加文件
fs.appendFileSync(path, data[, options])
5)创建文件夹
异步的创建文件夹
fs.mkdir("./data02",function(err){
console.log(err); //node会报错,但是错误都不会抛出,不会影响后续代码的执行
console.log('OK');
})
同步的创建文件夹
fs.mkdirSync(path[, options])
7)读文件夹
异步读文件夹
fs.readdir(path[, options], callback)
fs.readdir("./data",function(err,data){
console.log(err);
console.log(data); //里面的文件以数组的形式表示出来,进行判断,判断是否是文件夹
// 如果是文件夹,继续读文件夹,如果是文件,直接读文件,然后展示
})
同步的读文件夹
fs.readdirSync(path[, options])
8)文件夹是否存在
异步判断文件或者文件夹是否存在
fs.access(path[, mode], callback) 能否判断文件夹是否存在
fs.access("./data",function(err){ //这个方法是可以判断文件和文件夹是否存在
console.log(err);
console.log('OK');
})
同步判断文件或者文件夹是否存在
fs.accessSync(path[, mode])
9) 文件信息
fs.stat("./data",function(err,stats){
console.log(err);
// console.log(stats.isDirectory());
// 获取文件的大小;
if(stats.isDirectory()){
console.log('是文件夹')
}
else{
console.log('是文件')
}
console.log(stats.size);
// 获取文件最后一次访问的时间;
console.log(stats.atime.toLocaleString());
// 文件创建的时间;
console.log(stats.birthtime.toLocaleString());
// 文件最后一次修改时间;
console.log(stats.mtime.toLocaleString());
// 状态发生变化的时间;
console.log(stats.ctime.toLocaleString())
//判断是否是目录;是返回true;不是返回false;
console.log(stats.isFile())
console.log(stats.isDirectory())
})
})
10)文件流
想象一下,如果把文件读取比作向一个池子里抽水,同步会阻塞程序,异步会等待结果,如果这个池子特别大怎么办?有三峡水库那么大怎么办?你要等到多久才能喝到抽的水?因此便会有了文件流,文件流就好比你一边抽一边取,不用等池子满了再用一样方便。
// 文件流 适用于比较大内容 var fs = require("fs"); // 读文件的流 var rs = fs.createReadStream("./../0225-3node文件系统-1.mp4"); // 写文件的流 var ws = fs.createWriteStream("./video.mp4"); var stats = fs.statSync("./../0225-3node文件系统-1.mp4"); // console.log(stats); var size = stats.size; // 通过buffer进行传输 var data = 0; rs.on("data",function(chunk){ data = data + chunk.length; console.log('传输的进度' + (data/size) * 100 + "%"); ws.write(chunk); }) rs.on("end",function(){ console.log('文件读写完成'); ws.end(); })
// buffer 就是一个对象,有点像数组
var buf = new Buffer(5); //每一个存的值是16进制的
buf[0] = 0x68;
buf[1] = 0x65;
buf[2] = 0x6c;
buf[3] = 0x6c;
buf[4] = 0x6f;
2.http的模块:
// 引入http的模块
var http = require("http");
// 创建一个服务
var count = 0;
http.createServer(function(request,response){
count ++;
console.log('hello world');
response.end(count.toString())
}).listen(3000)
var path = require('path');
var filepath = '/tmp/demo/js/test.js';
console.log( path.dirname(filepath) )
// 输出:/tmp/demo/js
2)获取文件名:(basename)
var path = require('path');
console.log( path.basename('/tmp/demo/js/test.js') );
// 输出:test.js
//如果只想获取文件名,单不包括文件扩展呢?可以用上第二个参数。
console.log( path.basename('/tmp/demo/js/test.js', '.js') );
// 输出:test
//如果没有文件,获取路径的最后一位
console.log( path.basename('/tmp/demo/js/test/') );
// 输出:test
console.log( path.basename('/tmp/demo/js/test') );
// 输出:test
3) 获取文件扩展名
var path = require('path');
var filepath = '/tmp/demo/js/test.js';
console.log( path.extname(filepath) );
// 输出:.js
5.node服务器
var http = require("http"); //引入http的模块,用来提供服务 var fs = require("fs"); var server = http.createServer(); //创建一个服务器 //server监听request事件,callback server.on('request',function(request,response){ response.writeHead(200,{"Content-Type" : "text/html;charset=utf8"}); // 注意:图片,script,css,文本,html都要与之对应 // // 输出对应的中文的时候,要有对应的格式和对应的编码 // response.write("<h1>你好</h1>"); // response.end("<h2>hello world</h2>"); //结束,结束必须有,不然表示这个请求和响应没有完成 //接口设置 if(request.url == "/login.html" && request.method == "GET"){ // response.end("这个是登录界面") fs.readFile("./login.html",'utf8',function(err,data){ response.end(data); }) }else if(request.url == "/register" && request.method == "GET"){ response.end("这个是注册界面") } else if(request.url == "/login" && request.method == "POST"){ response.end("登录成功") } else { response.end("404"); } }); // 服务搭建完成,监听端口 server.listen(8888); //ctrl+c 停止 console.log('服务运行在localhost:8888')
2.服务器部分:
var http = require("http"); var fs = require("fs"); var querystring = require("querystring"); var url = require("url"); var path = require("path"); var server = http.createServer(); server.on("request",function(req,res){ var urlObj = url.parse(req.url,true); //地址栏格式化成对象 var pathname = urlObj.pathname; //pathname:当前页面的相对路径 var query = urlObj.query; console.log(pathname); //获取到地址栏的参数 //静态伺服 if(pathname == "/formlogin.html" && req.method == "GET"){ fs.readFile("./formlogin.html","utf8",function(err,data){ // console.log(err); res.end(data); }) } else if(pathname == "/register.html" && req.method == "GET"){ fs.readFile("./register.html","utf8",function(err,data){ // console.log(err); res.end(data); }) } else if(pathname == "/shouye.html" && req.method == "GET"){ fs.readFile("./shouye.html",function(err,data){ // console.log(err); res.end(data); }) } //js else if(pathname == "/js/formlogin.js" && req.method == "GET"){ fs.readFile("./js/formlogin.js","utf8",function(err,data){ // console.log(err); res.end(data); }) } else if(pathname == "/js/register.js" && req.method == "GET"){ fs.readFile("./js/register.js","utf8",function(err,data){ res.end(data); }) }else if(pathname == "/js/shouye.js" && req.method == "GET"){ fs.readFile("./js/shouye.js","utf8",function(err,data){ res.end(data); }) } //css else if(pathname == "/css/formlogin.css" && req.method == "GET"){ fs.readFile("./css/formlogin.css","utf8",function(err,data){ res.end(data); }) } else if(pathname == "/css/shouye.css" && req.method == "GET"){ fs.readFile("./css/shouye.css","utf8",function(err,data){ res.end(data); }) } //注册失焦验证 else if( pathname == "/register_validation" && req.method == "GET"){ fs.readFile("./data/03.json","utf8",function(err,datas){ var data = JSON.parse(datas); // console.log(data) var flag = true; //遍历数组,有相同名字的返回false,输出0;没有相同名字的,输出1; for(var i = 0; i < data.length; i++){ // console.log(query.uname); // console.log(data[i].uname); if(data[i].uname == query.uname){ // res.end("0"); //用户名已存在 flag = false; break; } } if(flag) { res.end("1"); //用户名可以使用 }else { res.end("0"); //用户名 } }) } //登录验证 else if(pathname == "/login" && req.method == "POST"){ // console.log('1111') var data =""; req.on("data",function(chunk){ data += chunk; }) req.on('end',function(){ var dataobj = querystring.parse(data); // console.log(dataobj); fs.readFile("./data/03.json","utf8",function(err,data){ data_login = JSON.parse(data); // console.log(data_login); // console.log(dataobj.uname); // console.log(dataobj.upassword); for(var i = 0; i < data_login.length; i++){ if(data_login[i].uname == dataobj.uname){ if(data_login[i].upassword == dataobj.upassword){ res.end("1"); //登录成功 }else { res.end("2"); //密码错误 } } } res.end("0"); //参数错误 }); }); } //注册按钮 else if(pathname == "/register" && req.method == "POST"){ var data =""; req.on("data",function(chunk){ data += chunk; }) console.log("1") req.on('end',function(){ var data_qt = querystring.parse(data); //用户输入的数据转化为对象的形式 console.log(data_qt); fs.readFile("./data/03.json","utf8",function(err,data){ // console.log(err); // console.log(data); if(data_qt.uname && data_qt.upassword){ var data_ht = JSON.parse(data); console.log(data_ht); //后台数据字符串转化为对象的形式 data_ht.push(data_qt); var data_ht_str = JSON.stringify(data_ht) fs.writeFile("./data/03.json",data_ht_str,"utf8",function(){ res.end("1") //注册成功 }); }else { res.end("0"); //参数错误 } }); }); } //获取主页数据 else if( pathname == "/index_getdata" && req.method == "GET" ){ fs.access("./data/"+query.uname+".json",function(err){ if(err){ fs.writeFile("./data/"+query.uname+".json","[]",function(err){ fs.readFile("./data/"+query.uname+".json","utf8",function(err,data){ var datas = '{"margin":"ok","data":'+data+'}'; // var bm =JSON.parse(datas); // console.log(bm) res.end(datas); }) }) }else { fs.readFile("./data/"+query.uname+".json","utf8",function(err,data){ var datas = '{"margin":"ok","data":'+data+'}'; // var bm = JSON.parse(datas); // console.log(bm) res.end(datas); }) } }) } //增加 else if(pathname == "/add_data" && req.method == "POST"){ var data =""; req.on("data",function(chunk){ //监听前台数据的变化 data += chunk; console.log(data); }) //字符串 req.on('end',function(){ var data_qt = querystring.parse(data); //用户输入的数据转化为对象的形式 console.log(data_qt); fs.readFile("./data/"+data_qt.uname+".json","utf8",function(err,datas){ console.log(err); // console.log(data); var data_ht = JSON.parse(datas); //后台数据字符串转化为对象的形式 console.log(data_ht); if(data_ht.length == 0){ data = { uname : data_qt.uname, pid:0, name:data_qt.name, sex:data_qt.sex, age:data_qt.age, mail:data_qt.mail, phone: data_qt.phone } data_ht.push(data); var data_ht_str = JSON.stringify(data_ht) fs.writeFile("./data/"+data_qt.uname+".json",data_ht_str,"utf8",function(){ res.end("1") //注册成功 }); }else { data = { uname : data_qt.uname, pid:data_ht[data_ht.length-1].pid+1, name:data_qt.name, sex:data_qt.sex, age:data_qt.age, mail:data_qt.mail, phone: data_qt.phone } data_ht.push(data); var data_ht_str = JSON.stringify(data_ht) fs.writeFile("./data/"+data_qt.uname+".json",data_ht_str,"utf8",function(){ res.end("1") //注册成功 }); } }); }); } //删除按钮 else if( pathname == "/remove_data" && req.method == "GET" ){ fs.readFile("./data/"+query.uname+".json","utf8",function(err,data){ var data = JSON.parse(data); var uname = query.uname; console.log(data); for (var i = 0; i < data.length; i++) { if (data[i].pid == query.pid) { // data.splice(i,1); console.log(i) break; } } // console.log(i) data.splice(i,1); // console.log(data); var data_str = JSON.stringify(data); // console.log(data_str); fs.writeFile('./data/' + uname + ".json",data_str,function(err){ res.end("1"); }) // console.log(data); }) } //修改 else if(pathname == "/revise_data" && req.method == "POST"){ var data_qt = ""; req.on("data",function(chunk){ data_qt += chunk; }) // console.log('1'); req.on('end',function(err){ // console.log("2"); var data_qt_obj = querystring.parse(data_qt); //用户输入的数据转化为对象的形式 // console.log(data_qt_obj) // var uname = data_qt_obj.uname; // var pid = data_qt_obj.pid; fs.readFile('./data/' + data_qt_obj.uname + ".json",'utf8',function(err,data){ var data_ht_obj = JSON.parse(data); // console.log(data_ht_obj); for(var i = 0;i < data_ht_obj.length;i++){ if(data_ht_obj[i].pid == data_qt_obj.pid){ break; } } if(data_qt_obj.name){ data_ht_obj[i].name = data_qt_obj.name } if(data_qt_obj.sex){ data_ht_obj[i].sex = data_qt_obj.sex } if(data_qt_obj.age){ data_ht_obj[i].age = data_qt_obj.age } if(data_qt_obj.mail){ data_ht_obj[i].mail = data_qt_obj.mail } if(data_qt_obj.phone){ data_ht_obj[i].phone = data_qt_obj.phone } var str = JSON.stringify(data_ht_obj); fs.writeFile('./data/' + data_qt_obj.uname + ".json",str,function(err){ res.end("1"); }) }) }) } }) server.listen(3535); console.log("server running in localhost:3535"); console.log("\n")