Node,js笔记
关于node的命令行
node -e 'js文本' 解析一段js文本
实时刷新: npm install supervisor -g
supervisor test.js
关于node的模块化:
node.js 不是一个框架,也不是一门语言,而是一个让javascriprt 运行在服务端的开发平台
在Node环境中,一个.js文件就称之为一个模块(module)。这种模块加载机制被称为CommonJS规范
在hello.js文件中:
function greet(name) { console.log(s + ', ' + name + '!'); } function getsame() { console.log('function') } module.exports = { // 导出模块 getsame, greet }
在main.js文件中:
var greet = require('./hello'); // 导入模块,相对路径 greet.greet('小妹') // 调用greet模块中的方法 greet.getsame()
关于node的基本模块:
global : 全局对象,类似于window
console : 输出对象
process : 表示当前node的进程,可以通过它得到当前的工作目录、执行进程等
process.cwd() 获得当前的工作目录
process.chdir('路径') 切换当前工作目录
process.on('exit' , function(){}) 在node程序即将执行完退出时进行的回调
process.nextTick() 在下一次事件循环中调用
process.nextTick(function () { // 在下一个事件执行完之后执行 console.log('nextTick'); }); console.log(console) // 执行完后执行process.nextTick() process.on('exit',function(code){ // 传入code 参数,表示执行结果 console.log(code) })
util :实用工具
util.inherits(fun1, fun2):实现两个对象之间的原型继承,推荐使用ES6的 class extends 代替
var util = require('util') function fun1 () { this.name = 'fun1' } function fun2 () { this.name = 'fun2' } fun1.prototype.showName = function() { // 定义原型方法 console.log(this.name) } util.inherits(fun1,fun2) // 使用inherits 进行原型继承 var test = new fun2(); test.showName(); // 调用继承过来的方法
showHidden: 布尔值,如果为true, 将输出更多详细信息
depth: Num值,表示标识最大的递归层数,即打印到第几层
colors:布尔值,如果为true,则打印出来的数据具备对应文本颜色(只有视觉效果作用)
var util = require('util') function obj () { this.name = 'object' this.fun = function() { console.log(this.name) } } console.log(util.inspect(obj,true,3,true)) // 输出 { [Function: obj] // [length]: 0, // [name]: 'obj', // [arguments]: null, // [caller]: null, // [prototype]: obj { [constructor]: [Circular] } }
关于node的内置模块:
读写文件:fs
fs : 文件系统模块,负责读写文件 fs
模块同时提供了异步和同步(Sync)的方法
try...catch
捕获该错误
fs.readFile('test.txt','utf-8',function(err, data){ // 读取纯文本,传入文件路径、编码格式 if(err){ // 回调方法传入两个参数。err为失败信息,data为读取到的数据 console.log('读取出错了'+err) } else { console.log('读取的数据内容为:'+data) } }) fs.readFile('img.jpg',function(err, data){ // 读取二进制文件,传入文件路径,获得的data是一个Buffer对象 if(err){ console.log('读取出错了'+err) } else { console.log(data); // 输出<Buffer ff d8 ff e0 00 10 4a 46 49 ... > } }) var data = fs.readFileSync('test.txt','utf-8') // 同步读取文件,没有回调函数,直接返回结果 try { var data = fs.readFileSync('sample.txt', 'utf-8'); console.log(data); } catch (err) { // 出错了 }
Buffer
对象就是一个包含零个或任意个字节的数组(注意和Array不同)
Buffer
对象可以和String作转换,例如,把一个Buffer
对象转换成String:
var text = data.toString('utf-8');
同时也可以把任意String转换成Buffer
对象:
var buf = new Buffer('这是一个utf-8编码格式的纯文本文件','utf-8'); console.log(buf) // 输出<Buffer e8 bf 99 e6 98 af e4 b8 80 ... >
fs.writeFile() 异步将数据写入文件 ,依次传入三个参数,分别为文件名、写入的数据、回调函数。回调函数只有成功与否一个参数,err 为 null 时表示成功 该方法写入的数据会替换原本的数据内容
fs.writeFileSync() 同步将数据写入文件
传入的数据是String,默认按UTF-8编码写入文本文件,如果传入的参数是Buffer
,则写入的是二进制文件。
var data = '这是新写入的数据内容' fs.writeFile('test.txt',data,function(err){ // 该方法会直接替换原本文件内的数据 if(err){ console.log('数据写入失败,错误为:'+err) } else { console.log('数据写入成功') } }) fs.readFile('test.txt','utf-8',function(err, data){ if(err){ console.log(err) } else { console.log(data) // 输出'这是新写入的数据内容' } })
fs.stat()
,获得文件的信息,它返回一个Stat
对象,记录文件或目录的详细信息,如文件大小、创建时间等 stat()
也有一个对应的同步函数statSync()
fs.stat('test.txt', function (err, stat) { if (err) { console.log(err); } else { console.log('isFile: ' + stat.isFile()); // 是否是文件: console.log('isDirectory: ' + stat.isDirectory()); // 是否是目录: if (stat.isFile()) { console.log('size: ' + stat.size); // 文件大小: console.log('birth time: ' + stat.birthtime); // 创建时间, Date对象: console.log('modified time: ' + stat.mtime); // 修改时间, Date对象: } } });
依次读写文件:stream : 流,分为标准输入流(stdin) 和 标准输出流(stdout) 流的特点是数据是有序的,而且必须依次读取,或者依次写入, 在Node.js中,流也是一个对象 配合fs 模块使用
所有可以读取数据的流都继承自stream.Readable
,所有可以写入的流都继承自stream.Writable
data
事件表示流的数据已经可以读取了,end
事件表示这个流已经到末尾了,没有数据可以读取了,error
事件表示出错了var fs = require('fs'); var rs = fs.createReadStream('test.txt','utf-8') // 打开一个可读取的流 rs.on('data', function(chunk){ //data表示已经在读取,该事件可能触发多次,每次传递的chunk是流的一部分数据。 console.log('DATA:'+chunk) }) rs.on('end', function(){ console.log('读取结束') }) rs.on('error',function(err){ console.log('读取错误:'+err) })
write()
方法,最后以end()
结束:var fs = require('fs'); var wsl = fs.createWriteStream('test.txt','utf-8') // 获得一个可写入的流 wsl.write('这是使用流写入的数据'); // 调用write() 方法写入数据,可调用多次 wsl.end(); // 写入结束 以 end() 方法声明 var ws2 = fs.createWriteStream('test.txt'); // 写入二进制数据 ws2.write(new Buffer('使用流写入二进制数据', 'utf-8')); ws2.end();
流的赋值:pipe 依次将一个流赋值给另一个流 pipe() 是读取流(Readable)的一个方法 其实就是复制 该方法写入的数据会替换原本的数据内容
var fs = require('fs'); var rs = fs.createReadStream('two.txt','utf-8') // 获得一个可读取的流 var ws = fs.createWriteStream('test.txt','utf-8') // 获得一个可写入的流 rs.pipe(ws) // 将读取流rs的数据复制到写入流ws ws原本的数据会被替换
默认情况下,当Readable
流的数据读取完毕,end
事件触发后,将自动关闭Writable
流。如果我们不希望自动关闭Writable
流,需要传入参数:{end : false}
readable.pipe(writable, { end: false });
解析前端传递路径:url 模块 通过 url.parse() 将url字符串解析为一个对象
'use strict'; var url = require('url'); console.log(url.parse('http://user:pass@host.com:8080/path/to/file?query=string#hash')); 结果如下: Url { protocol: 'http:', slashes: true, auth: 'user:pass', host: 'host.com:8080', port: '8080', hostname: 'host.com', hash: '#hash', search: '?query=string', query: 'query=string', pathname: '/path/to/file', path: '/path/to/file?query=string', href: 'http://user:pass@host.com:8080/path/to/file?query=string#hash' }
构造目录: path 模块 获得当前工作路径并对文件路径进行拼接
path.resolve() 解析当前的路径,传入相对路径参数
path.join() 将各个路径进行拼接 传入各个路径参数
'use strict'; var path = require('path'); var workDir = path.resolve('.'); // 解析当前目录: 输出'/Users/zhengweijie/projects/tests/node' var filePath = path.join(workDir, 'test.txt'); // 可以有多个参数 // 拼接路径 输出 /Users/zhengweijie/projects/tests/node/test.txt
服务器:http 模块
通过http.createServer模块就可以创建node服务器
request
对象封装了HTTP请求, 即前端发起的数据请求信息
response
对象封装了HTTP响应,即后台需要返回的数据信息server.on('connection',function(){ console.log('连接请求中') }) server.on('data',function(chunk){ console.log('接收请求中,接收参数chunk') }) server.on('end',function(chunk){ console.log('接收请求完成时') }) server.on('close',function(chunk){ console.log('接收请求结束时') })
'use strict'; var http = require('http'); // 导入http模块: // 创建http server,并传入回调函数: 回调函数接收 request 和 response 对象, var server = http.createServer(function (request, response) { //获得前端HTTP请求的请求方式method和请求地址url: console.log(request.method + ': ' + request.url); // 后台进行响应,将HTTP响应200写入response, 同时设置Content-Type: text/html: 响应头 response.writeHead(200, {'Content-Type': 'text/html'}); // 将HTTP响应的HTML内容写入response: 即返回的数据内容 响应内容 response.write('<h1>Hello world!</h1>'); // 将HTTP响应的HTML内容写入response: 即返回的数据内容 响应尾 response.end('<h1>end</h1>'); }); // 让服务器监听8080端口: 该端口所有的请求都会被创建的node服务监听到 server.listen(8080); console.log('Server is running at http://127.0.0.1:8080/');
'use strict' var http = require('http'); // 引入各个模块 var fs = require('fs'); var url = require('url'); var path = require('path') var workDir = path.resolve(process.argv[2] ||'.'); // 获得当前的工作目录 var server = http.createServer(function(request, response){ // 创建HTTP服务 console.log(request.method+':'+request.url) var pathName = url.parse(request.url).pathname // 获得发起请求的URl路径 var filePath = path.join(workDir, pathName) // 将当前目录与请求的路径拼接,得到文件路劲 console.log(filePath) fs.stat(filePath,function(err, stat){ // 使用该文件路径进行查询 if(!err && stat.isFile()){ console.log('200 读取成功'+request.url) response.writeHead(200) fs.createReadStream(filePath).pipe(response) // 直接使用流读取文件并赋值给 response 返回前端 } else { console.log('404 文件不存在') response.writeHead(404) response.end('404 Not Found') } }) }) server.listen(5858); console.log('runing now')
HTTP服务器程序扩展实例:post方式 使用 querystring
'use strict'; var http = require('http') var querystring = require('querystring') http.createServer(function(req,res){ var post = '' req.on('data',function(chunk){ post+=chunk }) req.on('end',function(){ post = querystring.parse(post) console.log('参数解析完成,返回name参数') res.end(post.name) }) }).listen(3000)
http模块提供了两个函数 http.request 和 http.get , 功能是作为客户端向HTTP服务器 发起请求(类似于ajax)
http.request(options, callback) 发起HTTP请求,需要接收两个参数,option是一个类数组对象,表示请求的参数,callback是请求的回调函数
callback 传递一个参数,为http.ClientResponse的实例;http.request 返回一个http.ClientRequest的实例
option常用参数:
host : 请求网站的域名和IP地址
port : 请求网站的端口,默认是80
method : 请求方法,默认是get
path :请求的相对于根的路径,默认是 ‘/’ QueryString应该包含在其中,例如 /search?query=test
headers : 一个关联数组对象,为请求头的内容
例子: (该例子执行报错)
'use strict'; var http = require('http') var querystring = require('querystring') // 启动服务 http.createServer(function(req,res){ var post = '' req.on('data',function(chunk){ // 解析post 参数 post+=chunk }) req.on('end',function(){ post = querystring.parse(post) console.log('参数解析完成,返回name参数') res.end(post.name) }) }).listen(3000) var contents = querystring.stringify({ // 声明 contents ,转为字符串 name:'test', age: 21, address: 'guangzhou' }); var options = { // 声明请求参数 host: 'localhost', path: '/', port: 3000, method: 'POST', headers: { 'Content-Type':'application/x-www-form-urlecoded', 'Content-length':contents.length } } // 客户端发起请求 var req = http.request(options,function(res){ res.setEncoding('utf-8') // 声明读取编码,默认是 Buffer res.on('data',function(data){ console.log('后台返回的数据:'+ data) }) }) req.write(contents) req.end() // 必须调用,表示请求结
http.get 是 http.request的简化版,区别在于http.get自动将请求方法设定为GET方式,同时不需要手动调用 req.end() 结束请求
例子: (该例子执行报错)
var http = require('http') var url = require('url') var util = require('util') // 启动服务 http.createServer(function(req,res){ console.log('请求到来,开始解析参数') var params = url.parse(req.url,true) console.log('解析完成') console.log(util.inspect(params)); console.log('向客户端返回') res.end(params.query.name) }).listen(2000) // 客户端发起请求 http.get({ host: 'localhost', path: '/user?name=test&age=21', port: 2000 },function(res){ res.setEncoding('utf-8') res.on('data',function(data){ console.log('返回的数据为:'+data) }) })
http.ClientRequest 该对象是由http.request或http.get返回产生的对象,表示一个已经产生而且正在进行的HTTP请求,它提供了response事件
提供的函数:
request.abort() 终止正在发送的请求
request.setTimeout(timeout, callback) 设置请求超时时间,timeout为毫秒数,当请求超时后,触发回调函数
事件模块 events 自定义各种事件
var EventEmitter = require('events').EventEmitter // 引入事件模块中的EventEmitter var event = new EventEmitter(); // new声明一个EventEmitter 对象 event event.on('some_event',function(){ // event.on 注册第一个自定义事件 console.log('这是第一个自定义事件') }) event.on('some_event',function(){ // event.on 注册第二个自定义事件 console.log('这是第二个自定义的事件') }) setTimeout(function(){ event.emit('some_event') // 使用 emit 调用注册的事件,会依次触发定义的方法 },1000)
常用的APi:
EventEmitter.on(eventName, function) 注册一个事件,接收事件名称和一个方法作为参数
EventEmitter.emit(eventName, [arg1], [arg2]...) 调用(发射)注册的事件,接收事件名和事件传入参数(可选)作为参数
EventEmitter.once(eventName, function) 类似于EventEmitter.on 注册事件,不过在调用一次后会自动解除,只能调用一次
EventEmitter.removeListener(eventName, funName) 移除注册事件中的某个事件,接收注册的事件名和移除的事件名两个参数
EventEmitter.removeAllListeners(eventName) 移除某个注册事件(整个移除),不传参数的请求下默认删除所有
EventEmitter.once 例子:
var EventEmitter = require('events').EventEmitter // 引入事件模块中的EventEmitter var event = new EventEmitter(); // new声明一个EventEmitter 对象 event event.once('some_event',function(){ console.log('这是调用EventEmitter.once的回调') }) event.on('some_event',function(name){ // event.on 注册第一个自定义事件 console.log('这是第一个自定义事件') console.log(name) }) setTimeout(function(){ event.emit('some_event') // 使用 emit 调用注册的事件,会依次触发定义的方法 event.emit('some_event') // 再次使用 emit 调用注册的事件,once定义的方法不再触发 },1000)
EventEmitter.removeListener:例子:
var EventEmitter = require('events').EventEmitter // 引入事件模块中的EventEmitter var event = new EventEmitter(); // new声明一个EventEmitter 对象 event const fun1 = function(){ console.log('这是第一个自定义事件') } const fun2 = function(name){ // event.on 注册第一个自定义事件 console.log('这是第二个自定义事件') console.log(name) } event.on('some_event',fun1) event.on('some_event',fun2) event.removeListener('some_event',fun1) // 使用removeListener 移除定义的事件 event.emit('some_event') // 使用 emit 调用注册的事件,会依次触发定义的方法,没有fun2
EventEmitter.removeAllListeners 例子:
var EventEmitter = require('events').EventEmitter // 引入事件模块中的EventEmitter var event = new EventEmitter(); // new声明一个EventEmitter 对象 event const fun1 = function(){ console.log('这是第一个注册事件') } const fun2 = function(name){ console.log('这是第二个注册事件') console.log(name) } event.on('some_one',fun1) event.on('some_two',fun2) event.removeAllListeners('some_one') // 使用removeAllListeners 移除注册的事件,不传参数为删除全部 event.emit('some_one') // 使用 emit 调用注册的事件,不存在事件,已被移除 event.emit('some_two') // 使用 emit 调用注册的事件