Node.js入门笔记整理

1.入门

node是一个基于Chrome V8引擎的javascript运行环境,是运行在服务器端的javascript
可以使用node搭建服务器,连接数据库。让前端开发人员走向后端开发。
Node.js使用了一个事件驱动、非阻塞I/O口,使其轻量且高效
Node的包管理工具npm,是全球最大的开源库生态系统

1.1 简介

1.2 安装

检查是否安装好环境
在这里插入图片描述

1.3 交互式解释器REPL

Node 自带了交互式解释器,可以执行以下任务:
读取 - 读取用户输入,解析输入了Javascript 数据结构并存储在内存中
执行 - 执行输入的数据结构
打印 - 输出结果
循环 - 循环操作以上步骤直到用户两次按下 ctrl-c 按钮退出
通过node命令进入交互式解析器

在这里插入图片描述

1.4 http模块创建服务

新建一个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('<h3>hello world!这是Node.js入门的小测试</h3>');
	
}).listen(3000)

console.log('请求成功,输入localhost:3000访问')

在这里插入图片描述
在这里插入图片描述

1.5 文件模块

引入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('正在读取文件....')

在这里插入图片描述

2.事件循环

2.1 简介

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

2.2 测试

测试多个参数

//引入事件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)

在这里插入图片描述

event事件的执行顺序只和其触发的先后顺序有关
在这里插入图片描述

同一个事件名绑定多个事件:哪个先绑定,哪个先执行
在这里插入图片描述
在这里插入图片描述
on 和addListener区别:

  • on监听的事件不能移除
  • addListener监听事件可以使用removeListener或removeAllListener进行移除

在这里插入图片描述

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'))

在这里插入图片描述

3.自定义模块

3.1 简介

模块系统的作用主要体现在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的具体实现。

在这里插入图片描述

3.2 简单测试自定义模块

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()

在这里插入图片描述

3.3 自定义模块封装一个学校(难)

这部分的代码较难,多读几遍
目录:
在这里插入图片描述
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:['迪卢克','迪奥娜','可莉','雷泽','凯亚'],
			},
		]
	}
	)

测试:
在这里插入图片描述

4.路由

4.1 url模块

url模块常见方法

parse()将url地址转换为对象
    第一个参数:解析的url地址(路径)
    第二个参数:query的值是否为对象
        true->对象     false->字符串
    第三个参数:是否正确识别无协议的url地址
        true->识别     false->不识别
        
format(obj)将对象转换为url地址
resolve()将路径和文件进行拼接

url.parse解析出来的对象属性参考:
在这里插入图片描述
导入url模块

var url =require('url')
console.log(url)

在这里插入图片描述
parse()测试:

第一个参数:解析的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)

在这里插入图片描述
给上参数true

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)

在这里插入图片描述
测试resolve():

var url =require('url')
var path =url.resolve('http://www.jd.com','login')
console.log(path)

在这里插入图片描述

4.2 querystring模块

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))

在这里插入图片描述
stringify()

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

在这里插入图片描述
parse()

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,',','=>'))

在这里插入图片描述

4.3 封装一个路由

需求:

  • 实现游览器输入那个路径就跳转到对应文件目录下的html文件页面
  • 如果页面不存在就跳转到404页面

效果演示:

目录结构:
在这里插入图片描述

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')

到此,路由封装完成!

5.GET/POST

5.1 get测试

在这里插入图片描述

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访问')

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.2 post测试

在这里插入图片描述

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访问')

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6.全局对象

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

console方法
在这里插入图片描述

7.文件系统

这部分更详细的知识点可以查看菜鸟教程
https://www.runoob.com/nodejs/nodejs-fs.html

7.1 入门

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

7.2 文件的基本操作

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())
		})
	})
})

在这里插入图片描述

在这里插入图片描述

7.3 递归实现文件的读取、拷贝和删除

目录结构:
在这里插入图片描述
文件的读取
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')
````
  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值