node是一个基于Chrome V8引擎的javascript运行环境,是运行在服务器端的javascript
可以使用node搭建服务器,连接数据库。让前端开发人员走向后端开发。
Node.js使用了一个事件驱动、非阻塞I/O口,使其轻量且高效
Node的包管理工具npm,是全球最大的开源库生态系统
检查是否安装好环境
Node 自带了交互式解释器,可以执行以下任务:
读取 - 读取用户输入,解析输入了Javascript 数据结构并存储在内存中
执行 - 执行输入的数据结构
打印 - 输出结果
循环 - 循环操作以上步骤直到用户两次按下 ctrl-c 按钮退出
通过node命令进入交互式解析器
新建一个js文件,引入http模块
var http = require('http');
console.log(http)
打开js文件所在的目录运行此文件,下面的结果就是输出的http的内容
创建服务
输出的结果中有创建服务这一项
var http = require('http');
// console.log(http)
http.createServer(function(request,response){
// request为请求 response为响应
// 发送数据
response.end('hello world!');
}).listen(3000)
console.log('请求成功,输入localhost:3000访问')
设置writeHead 响应请求头
参数一:http状态码 200 Ok
参数二:内容的类型
text/plain 文本
text/html html标记语言(建议使用)
text/json json数据
text/url-list url列表
response方法:
write() 写入数据到页面,可以重复使用,但不能放到end之后
end() 一个服务只能出现一次,且end后面的代码将不会被执行
response.writeHead(200,{'content-type':'text/html;charset=utf-8'})
例子:
var http = require('http');
// console.log(http)
http.createServer(function(request,response){
// request为请求 response为响应
response.writeHead(200,{'content-type':'text/html;charset=utf-8'})
response.write('1111')
// 发送数据
response.end('hello world!这是Node.js入门的小测试
');
}).listen(3000)
console.log('请求成功,输入localhost:3000访问')
引入fs模块
// 引入文件模块fs
var fs=require('fs')
console.log(fs)
创建一个文件并读取
// 引入文件模块fs
var fs=require('fs')
// console.log(fs)
// 阻塞代码 同步读取文件
var data =fs.readFileSync('genshin.txt')
console.log(data.toString())
console.log('正在读取文件....')
在这里插入图片描述
var fs=require('fs')
//fs.readFile(path,callack)异步读取文件内容 data为异步读取的文件数据
fs.readFile('genshin.txt',function(err,data){
if(err) return console.error(err);
console.log(data.toString())
})
console.log('正在读取文件....')
Node.js 是单进程单线程应用程序,但是因为 V8 引擎提供的异步执行回调接口,通过这些接口可以处理大量的并发,所以性能非常高。
Node的所有API都支持回调函数
Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现
//1.引入事件events模块
var events=require('events')
//2.创建一个EventEmitter对象
var emitter=new events.EventEmitter();
//3.emitter.on(eventName,handler)监听事件
emitter.on('connect',function(){
console.log('连接成功')
})
//4.emitter.emit(eventName)触发事件
setTimeout(function(){
emitter.emit('connect')
},1000)
注意:
1、event事件的执行顺序只和其触发的先后顺序有关
2、event允许同一个事件名同时绑定多个监听器,且依次触发
3、eventEmitter的每个事件允许传入若干个参数
事件方法:
on(event,listener) 为一个指定的事件注册监听器
emit(event,[arg1],[arg2],[arg3]...)按监听器的顺序执行执行每个监听器
addListener(event, listener)为指定事件添加一个监听器到监听器数组的尾部
once(event,listener)为指定事件添加一个单次监听器
removeListener(event,listener)移除指定事件的某一个监听器
removeAllListeners(event)移除指定事件所有的监听器
listeners(event)返回指定事件的监听器数组
listenerCount(emitter,event)返回指定事件当前监听器的数量
语法:events.EventEmitter.listenerCount(emitter,event)
setMaxListeners(n)设置最大的监听器个数 默认为10个
测试多个参数:
//引入事件events模块
var events=require('events')
//创建一个EventEmitter对象
var emitter=new events.EventEmitter();
//emitter.on(eventName,handler)监听事件
emitter.on('connect',function(a,b){
console.log('连接成功')
console.log(a)
console.log(b)
})
//emitter.emit(eventName)触发事件
setTimeout(function(){
emitter.emit('connect','钟离','胡桃')
},1000)
同一个事件名绑定多个事件:哪个先绑定,哪个先执行
on 和addListener区别:
var events=require('events');
var emitter=new events.EventEmitter();
function listener1(){
console.log('监听器1')
}
function listener2(){
console.log('监听器2')
}
function listener3(){
console.log('监听器3')
}
emitter.addListener('connect',listener1)
emitter.addListener('connect',listener2)
emitter.addListener('connect',listener3)
emitter.emit('connect')
//listeners返回一个事件数组
console.log(emitter.listeners('connect'))//[ [Function: listener1], [Function: listener2], [Function: listener3] ]
var listenerNum=events.EventEmitter.listenerCount(emitter,'connect');
console.log(`当前监听器的数量为:${listenerNum}`)//当前监听器的数量为:3
//移除指定的单个监听器removeListener(eventName,Listener)
emitter.removeListener('connect',listener2)
console.log(emitter.listeners('connect'))//[ [Function: listener1], [Function: listener3] ]
//移除指定所有的建ring器removeAllListeners(eventName)
emitter.removeAllListeners('connect')
console.log(emitter.listeners('connect'))
模块系统的作用主要体现在Node.js的文件的相互调用。
模块系统是Node的基本组成部分,每一个Node.js文件则为一个模块
常见的模块:http、fs、events、url、queryString
步骤:
(1) 创建模块 导出的模块可以为函数、对象...
(2) 导出模块 exports module.exports
(3) 引入模块 require(属于Common.js的语法)
(4) 使用模块
exports和module.exports的区别?
exports是module.exports的抽象化代表,module.exports是exports的具体实现。
hello.js
function hello(){
console.log('大丘丘病了二球球瞧')
}
//expoprts.模块名=导出的内容
exports.hello=hello;
3.js
var hello =require('./hello');
console.log(hello)
var hello =require('./hello');
// console.log(hello)
hello.hello()
这部分的代码较难,多读几遍
目录:
student.js
function add(studentName){
console.log(`学生:${studentName}`)
}
// add('胡桃')
module.exports.add=add;
teacher.js
function add(teacherName){
console.log(`老大叫:${teacherName}`)
}
// add('胡桃')
module.exports.add=add;
classroom.js(这部分开始就比较难理解了)
var teacher=require('./teacher')
var student=require('./student')
function add(className,teacherName,students){
console.log(`班级名字为:${className}`)
teacher.add(teacherName)
for(var i=0;i<students.length;i++){
student.add(students[i])
}
}
add('璃月','钟离',['胡桃','行秋','七七','刻晴'])
module.exports.add=add
因为后面还要封装一个学校school.js,所以需要对classroom.js这部分的代码做一定的修改
var teacher=require('./teacher')
var student=require('./student')
function add(obj){
console.log(`班级名字为:${obj.className}`)
teacher.add(obj.teacherName)
for(var i=0;i<obj.students.length;i++){
student.add(obj.students[i])
}
console.log('======================================')
}
// add('璃月','钟离',['胡桃','行秋','七七','刻晴'])
module.exports.add=add
school.js
var classroom =require('./classroom')
function add(obj){
console.log(`学校名:${obj.school}`)
for(var i=0;i<obj.classroom.length;i++){
classroom.add(obj.classroom[i])
}
}
add({
school:'提瓦特',
classroom:[
{
className:'璃月',
teacherName:'钟离',
students:['行秋','胡桃','七七','刻晴','凝光'],
},
{
className:'蒙德',
teacherName:'温蒂',
students:['迪卢克','迪奥娜','可莉','雷泽','凯亚'],
},
]
}
)
url模块常见方法
parse()将url地址转换为对象
第一个参数:解析的url地址(路径)
第二个参数:query的值是否为对象
true->对象 false->字符串
第三个参数:是否正确识别无协议的url地址
true->识别 false->不识别
format(obj)将对象转换为url地址
resolve()将路径和文件进行拼接
url.parse解析出来的对象属性参考:
导入url模块
var url =require('url')
console.log(url)
第一个参数:解析的url地址(路径)
var url =require('url')
// console.log(url)
var str ='http://www.taobao.com';
console.log(url.parse(str))
第二个参数:query的值是否为对象
true->对象 false->字符串
var url =require('url')
var str='http://www.jd.com:8080?name=aaa&pass=123';
var obj=url.parse(str)
console.log(obj)
console.log(obj.query)
var url =require('url')
var str='http://www.jd.com:8080?name=aaa&pass=123';
var obj=url.parse(str,true)
console.log(obj)
console.log(obj.query)
console.log(obj.query.name)
var url =require('url')
var str='http://www.jd.com:8080?name=aaa&pass=123';
var obj=url.parse(str,true,true)
console.log(obj)
format()测试:
var url =require('url')
var obj={
protocol: 'http:',
slashes: true,
auth: null,
host: 'www.taobao.com',
port: null,
hostname: 'www.taobao.com',
hash: null,
search: null,
query: null,
pathname: '/',
path: '/',
href: 'http://www.taobao.com/'
}
var path=url.format(obj)
console.log(path)
var url =require('url')
var path =url.resolve('http://www.jd.com','login')
console.log(path)
var querystring=require('querystring')
console.log(querystring)
escape()将中文字符进行编码
unescape()将编码进行解码转换为中文字符
stringify()序列化(将对象转换为字符串)
第一个参数:需要转换的对象
第二个参数:键值对的连接方式
第三个参数:键和值的连接方式
parse()反序列化(将字符串转换为对象)
第一个参数:需要转换的字符串
第二个参数:键值对的拆分方式
第三个参数:键和值的拆分方式
escape(), unescape()
var querystring=require('querystring')
// console.log(querystring)
var str ="大丘丘病了二丘丘瞧";
console.log(querystring.escape(str))
var str ="%E5%A4%A7%E4%B8%98%E4%B8%98%E7%97%85%E4%BA%86%E4%BA%8C%E4%B8%98%E4%B8%98%E7%9E%A7";
console.log(querystring.unescape(str))
var querystring=require('querystring')
var obj={
name:'Amy',
pass:123456
}
console.log(querystring.stringify(obj))name=Amy&pass=123456
console.log(querystring.stringify(obj,','))//name=Amy,pass=123456
console.log(querystring.stringify(obj,',','=>'))//name=>Amy,pass=>123456
var querystring=require('querystring')
var str="name=Amy&pass=123456";
var str1="name=Amy,pass=123456";
var str2="name=>Amy,pass=>123456";
console.log(querystring.parse(str))
console.log(querystring.parse(str1,','))
console.log(querystring.parse(str2,',','=>'))
需求:
效果演示:
var http=require('http');
var url =require('url')
var fs=require('fs')
http.createServer(function(req,res){
//设置请求头
res.writeHead(200,{'content-type':'text/html;charset=utf-8'})
//解析req.url
var resName=url.parse(req.url).pathname
if(resName=='/favicon.ico'){
return
}else if(resName=='/'){
fs.readFile('./pages/index.html',function(err,data){
if(err) return console.error(err)
//读取到的信息进行响应
res.write(data)
res.end('响应完成!')
})
}
}).listen(3000)
console.log('serve is running at localhost:3000')
以上代码便可以访问到根路径
要实现访问多个页面就会重复写好几次的文件读取部分的代码,所以对这部分代码进行封装
read.js
//引入文件模块
var fs=require('fs')
function read(path,res){//两个参数,一个路径,一个response
//如果读取的文件找不到就跳转到404页面
fs.readFile(path,function(err,data){
if(err) {
var newPath ='./pages/error.html'
read(newPath,res)
}else{
//读取到的信息进行响应
res.write(data)
res.end('响应完成!')
}
})
}
module.exports.read=read
var http=require('http');
var url =require('url')
//引入自定义读取文件模块
var read=require('./read')
//定义首页
var index ='./pages/index.html'
http.createServer(function(req,res){
//设置请求头
res.writeHead(200,{'content-type':'text/html;charset=utf-8'})
//解析req.url
var resName=url.parse(req.url).pathname
if(resName=='/favicon.ico'){
return
}else if(resName=='/'){
read.read(index,res)
}else{
//模板字面量凭借路径
var path=`./pages${resName}.html`
read.read(path,res)
}
}).listen(3000)
console.log('serve is running at localhost:3000')
到此,路由封装完成!
get.html
DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>title>
head>
<body>
<form action="http://localhost:3000" method="get">
name:<input type="text" name="name" id="name"/><br>
pass:<input type="password" name="pass" id="pass"/><br>
<input type="submit"/>
form>
body>
html>
var http = require('http');
var url=require('url')
http.createServer(function(request,response){
// request为请求 response为响应
response.writeHead(200,{'content-type':'text/html;charset=utf-8'})
//get请求
var data=url.parse(request.url,true).query;
console.log(data)
// 发送数据
response.end();
}).listen(3000)
console.log('请求成功,输入localhost:3000访问')
post.html
DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>title>
head>
<body>
<form action="http://localhost:3000" method="post">
name:<input type="text" name="name" id="name"/><br>
pass:<input type="password" name="pass" id="pass"/><br>
<input type="submit"/>
form>
body>
html>
var http = require('http');
var querystring=require('querystring')
http.createServer(function(request,response){
// request为请求 response为响应
response.writeHead(200,{'content-type':'text/html;charset=utf-8'})
//定义一个变量接收所有post传递的数据
var post='';
//post请求
//data事件在有数据传输时,自定触发
request.on('data',function(chunk){
post+=chunk
})
// 发送数据
request.on('end',function(){
console.log(post)
//将post的数据转换为对象,data为解析后的post传递的数据
var data =querystring.parse(post)
console.log(data)
response.end()
})
}).listen(3000)
console.log('请求成功,输入localhost:3000访问')
javascript有个特殊的对象叫做全局对象(window),他的所有属性在任何地方都可以访问,也叫做全局变量。
在node.js中,全局对象为(global),所有的全局变量都属于该对象。
注意:在node.js中,你不可能在最外层定义变量,因为所有的变量都属于当前模块
__filename 表示当前正在执行的脚本的文件名
__dirname 表示当前正在执行的脚本的文件目录
setTimeout()
clearTimeout()
setInterval()
clearInterval()
console()
//表示当前正在执行的脚本文件名,注意是两个'_'
console.log(__filename);//D:\environment\wamp\www\H5\Node.js\2021.11.15\1.js
//表示当前执行脚本所在的目录
console.log(__dirname)//D:\environment\wamp\www\H5\Node.js\2021.11.15
这部分更详细的知识点可以查看菜鸟教程
https://www.runoob.com/nodejs/nodejs-fs.html
Node.js 文件系统(fs 模块)模块中的方法均有异步和同步版本,例如读取文件内容的函数有异步的 fs.readFile() 和同步的 fs.readFileSync()
异步的方法函数最后一个参数为回调函数,回调函数的第一个参数包含了错误信息(error)
引入文件模块
var fs = require('fs');
文件的操作
fs.open(path, flags[, mode], callback)打开文件
fs.close(fd, callback)关闭文件
fs.writeFile(file, data[, options], callback)写入文件
fs.readFile(filename,[option],callback)读取文件
fs.unlink(path, callback)删除文件
目录操作
fs.mkdir(path[, options], callback)创建目录
fs.readdir(path, callback)读取目录 返回files为目录下文件的数组列表
fs.rmdir(path, callback)删除目录
检测文件的状态
fs.stat(path, callback)获取文件信息
stats
stats.isFile()判断该路径是否为文件
stats.isDirectory()判断该路径是否为目录
stats.isSocket()判断是否返回socket
var fs=require('fs');
//打开文件
fs.open('input.txt','a+',function(err,fd){
if(err) return console.error(err)
// 写入文件
fs.writeFile('input.txt','hello node!',{flag:'a+'},function(err){
if(err) return console.error(err)
//读取文件
fs.readFile('input.txt',function(err,data){
if(err) return console.error(err)
console.log(data.toString())
})
})
//关闭文件
fs.close(fd,function(err){
if(err) return console.error(err)
//删除文件
setTimeout(function(){
fs.unlink('input.txt',function(err){
if(err) return console.error(err)
})
},1000)
})
})
//读取文件目录
fs.readdir('../get',function(err,files){
if(err) return console.error(err)
console.log(files)//[ 'get.html', 'get.js' ]
//循环判断当前文件是否为目录
files.forEach(function(file){
fs.stat('../get',function(err,stats){
if(err) return console.error(err)
console.log('是文件嘛?'+stats.isFile())
console.log('是目录嘛?'+stats.isDirectory())
})
})
})
目录结构:
文件的读取
file.js
var fs =require('fs');
function read(path){
//读取当前目录中的文件
fs.readdir(path,function(err,files){
if(err) return console.error(err)
// console.log(files)
// 循环files得到每一个文件路径
files.forEach(function(file){
// console.log(file)
var newPath=path+'/'+file;
// console.log(newPath)
//检测当前的路径是否为文件?直接输出:继续读取
fs.stat(newPath,function(err,stats){
if(err) return console.error(err)
// console.log(stats.isFile())
if(stats.isFile()){
//该路径为文件
console.log(newPath)
}else{
//该路径为文件夹
/**
* 打开当前文件夹,
* 循环文件夹内的文件
* 判断是否为文件?直接输出:继续读取
*/
//递归读取文件
read(newPath)
}
})
})
})
}
read('./files')
var fs =require('fs');
function copy(path,dist){
//创建文件夹,用来装复制后的文件
fs.mkdir(dist+path,function(err){
if(err) return console.error(err)
})
//读取当前目录中的文件
fs.readdir(path,function(err,files){
if(err) return console.error(err)
// console.log(files)
// 循环files得到每一个文件路径
files.forEach(function(file){
// console.log(file)
var newPath=path+'/'+file;
// console.log(newPath)
//检测当前的路径是否为文件?直接输出:继续读取
fs.stat(newPath,function(err,stats){
if(err) return console.error(err)
// console.log(stats.isFile())
if(stats.isFile()){
//该路径为文件
// console.log(newPath)
// 读取文件内容
fs.readFile(newPath,function(err,data){
if (err) return console.error(err)
//将读取的内容写入文件
fs.writeFile(dist+newPath,data,{flag:'w+'},function(err){
if(err) return console.log(err)
// console.log(data.toString())
})
})
}else{
//该路径为文件夹
/**
* 打开当前文件夹,
* 循环文件夹内的文件
* 判断是否为文件?直接输出:继续读取
*/
//递归读取文件
copy(newPath,dist)
}
})
})
})
}
copy('./files','../')
var fs =require('fs');
function del(path){
//读取当前目录中的文件
fs.readdir(path,function(err,files){
if(err) return console.error(err)
// console.log(files)
// 循环files得到每一个文件路径
files.forEach(function(file){
// console.log(file)
var newPath=path+'/'+file;
// console.log(newPath)
//检测当前的路径是否为文件?直接输出:继续读取
fs.stat(newPath,function(err,stats){
if(err) return console.error(err)
// console.log(stats.isFile())
if(stats.isFile()){
//该路径为文件
// console.log(newPath)
fs.unlink(newPath,function(err){
if(err) return console.error(err)
})
}else{
//该路径为文件夹
/**
* 打开当前文件夹,
* 循环文件夹内的文件
* 判断是否为文件?直接输出:继续读取
*/
//递归读取文件
del(newPath)
}
})
})
})
}
del('../files')
上面这种删除的写法只是简单的把文件删除了,而且还是异步删除的,没有实现把目录也删除了。所以需要换一种写法。
var fs =require('fs');
function del(path){
//读取当前目录中的文件
var files =fs.readdirSync(path);
files.forEach(function(file){
//判断当前文件是否文件类型
var newPath=path+'/'+file;
var stats=fs.statSync(newPath)
// console.log(stats)
if(stats.isFile()){
fs.unlinkSync(newPath)
}else{
del(newPath)
}
})
//删除文件夹,只能删除空文件夹
fs.rmdirSync(path)
}
del('../files')
````