https://study.163.com/course/courseLearn.htm?courseId=1210098848#/learn/video?lessonId=1281066155&courseId=1210098848
node.js是基于JavaScript的运行环境,使用的是google v8的引擎
使用事件驱动和异步的非阻塞I/O模型
前端学习会比较方便,因为语言语法是一样的,只是api不一样,面向的功能不一样,对于前段来说可以简单的去定义接口api
可以参考菜鸟教程的nodejs安装,个人觉得写得很详细了,而且电脑已经安装过就不实操了
https://www.runoob.com/nodejs/nodejs-install-setup.html
在命令行中输入node之后会打开交互解释器
类似浏览器的控制台的使用
下划线_
可以方便的复制上一条输出
另外.help里面还有很多方法
直接在vscode中创建js文件,正常执行即可,也可以用vscode的插件
node demo1.js
npm一般是包括在nodejs中的,是我们对项目依赖包的快速下载
记得安装淘宝镜像源
npm install XXX -g
全局安装
npm install XXX --save
依赖到项目
下面试一下express
新建demo01.js
// 使用express和npm
// npm install express --save
let express=require('express')
let app=express()
app.get('/',(req,res)=>{
res.send('hello')
})
app.listen(8000,()=>{
console.log("启动",'http://localhost:8000')
})
在命令行运行
node demo01.js
commonjs
文件即模块
通过require引入exports导出的模块
新建demo02
也可以这样导出
不过还是推荐用module.exports
的形式优先级要高一些而且两种同时用会乱掉
在require中使用相对路径引用自己写的文件
如果没有相对路径会优先找当前目录下的node_modules,逐级往上找
就是我们node_modules中的一个目录形成的模块,配置信息一般在package.json
npm init
用来自定初始化包
nodejs是服务器语言,所以一定可以使用file
即node中的fs
模块
const fs = require('fs')
新建demo03
下面先使用同步的方式来写入一个文件(等待写入完成才会有下一步)
const fs =require('fs')
//同步打开文件
let fd=fs.openSync('./test1.txt','w')
console.log(fd)
//写入内容
let str ='hello\n'
fs.writeFileSync(fd,str)
//退出文件
fs.closeSync(fd)
下面来试试异步的文件写入
const fs =require('fs')
//异步打开,使用回调函数
fs.open('text2.txt','w',(err,fd)=>{
fs.writeFile(fd,'hello2',(err)=>{
if(err){
console.log(err)
}
fs.close(fd,(err)=>{
if(err){
console.log(err)
}
console.log('关闭完成')
})
})
})
console.log('index2')
下面是同步和异步的区别
同步和异步是相对于操作结果来说,会不会等待结果返回
阻塞就是在等待时你不可以去干其他的事情,非阻塞就是在同样的情况下,可以同时去干其他的事情。阻塞和非阻塞是相对于线程是否被阻塞。
文件还可以使用流写入
读出来的是buffer二进制数据的形式,转化成字符串就行了
下面尝试把一张图片读入再写入
新建index5.js,引入test.png
let fs=require('fs')
let rs=fs.createReadStream('./test.png')
let ws=fs.createWriteStream('./test_p.png')
//创建管道,读取流入到管道到写出流
rs.pipe(ws)
console.log('index7')
和上面index6的效果一样但是简便很多,用到pipe管道函数
同样是使用fs
文件系统
删除文件用unlink,读取目录用readdir
let fs=require('fs')
//创建文件夹
fs.mkdir('./img',(err)=>{
if(err){
console.log(err)
}else{
console.log('目录创建成功')
}
})
//删除文件夹,只能是空的
fs.rmdir('./img',(err)=>{
if(err){
console.log(err)
}else{
console.log('目录删除成功')
}
})
但是如果目录下面有文件,是不能直接删除的,所以需要我们递归把目录下的子级目录和文件删除
新建一个目录
let fs = require("fs");
//删除非空目录(使用递归)
function delDir(dirPath) {
let fileArr = fs.readdirSync(dirPath);
//拿到目录列表
console.log(dirPath + "~目录列表:", fileArr);
fileArr.forEach((item) => {
//可能是文件或者目录
let filePath = dirPath + "/" + item;
console.log(dirPath + ":", filePath);
//读取文件或目录信息
let stat = fs.statSync(filePath);
if (stat.isFile()) {
fs.unlinkSync(filePath);
} else if (stat.isDirectory()) {
delDir(filePath);
}
});
//删除本目录
fs.rmdirSync(dirPath);
}
delDir("./目录");
console.log("index10");
//控制台输出如下
PS D:\准备\老陈安排\nodejs基础\demo03> node index10.js
./目录~目录列表: [ 'text1.txt', 'text2.txt', 'text3.txt', '目录1', '目录2' ]
./目录: ./目录/text1.txt
./目录: ./目录/text2.txt
./目录: ./目录/text3.txt
./目录: ./目录/目录1
./目录/目录1~目录列表: [ 'text1.txt', '目录4' ]
./目录/目录1: ./目录/目录1/text1.txt
./目录/目录1: ./目录/目录1/目录4
./目录/目录1/目录4~目录列表: []
./目录: ./目录/目录2
./目录/目录2~目录列表: [ 'text2.txt', '目录3' ]
./目录/目录2: ./目录/目录2/text2.txt
./目录/目录2: ./目录/目录2/目录3
./目录/目录2/目录3~目录列表: [ 'text3.txt' ]
./目录/目录2/目录3: ./目录/目录2/目录3/text3.txt
index10
触发事件的形式
其中有事件循环机制
也可以用events模块自定义事件
let events =require('events')
//创建事件对象
let eventLog=new events.EventEmitter();
eventLog.on('lcMkDir',()=>{//触发时执行的函数
console.log('lcMkDir','触发')
})
//触发事件
eventLog.emit('lcMkDir')
还可以携带多个参数
let events =require('events')
//创建事件对象
let eventLog=new events.EventEmitter();
eventLog.on('lcMkDir',()=>{//触发时执行的函数
console.log('lcMkDir','触发')
})
eventLog.on('lcMkDir',(...args)=>{
console.log('lcMkDir','带参数触发',args)
})
//触发事件
eventLog.emit('lcMkDir',{
data:'msg'
},666)
node的读取流都是二进制data,默认的我们需要buffer缓冲区操作
//创建buffer,buffer.from()
let b1=Buffer.from('10')
console.log(b1)
console.log(b1.toString())
//初始化缓冲区
let b2=Buffer.alloc(10);//创建大小为10字节的缓冲区
console.log(b2);//重置为0的缓冲区
let b3=Buffer.allocUnsafe(10);//创建大小为10字节的缓冲区但是不重置
console.log(b3)
主要使用child_process模块
child_process.exec(command[, options], callback)
//index1.js
console.log('进程:'+process.argv[2]+'执行')
//main1.js
const child_process=require("child_process")
for(var i=0;i<3;i++){
//分别开启新进程去执行index1.js
var workerProcess=child_process.exec('node index1.js '+i,function(err,stdout,stderr){
if(err){
console.log(err)
}else{
console.log('stdout',stdout)
console.log('stderr',stderr)
}const child_process=require("child_process")
for(var i=0;i<3;i++){
//分别开启新进程去执行index1.js
var workerProcess=child_process.exec('node index1.js '+i,function(err,stdout,stderr){
if(err){
console.log(err)
}else{
//stdout拿到子进程输出结果
//stderr拿到子进程错误信息
console.log('stdout',stdout)
console.log('stderr',stderr)
}
})
workerProcess.on('exit',(code)=>{
console.log('退出'+code)
})
}
})
}
child_process.spawn(command[, args][, options])
const child_process=require("child_process")
for(var i=0;i<3;i++){
//分别开启新进程去执行index1.js
var workerProcess=child_process.spawn('node',['./index1.js',i])
workerProcess.on('close',(code)=>{
console.log('退出'+code)
})
workerProcess.stdout.on('data',(data)=>{
console.log(data.toString())
})
workerProcess.stderr.on('data',(err)=>{
console.log(err)
})
}
另外进程通信可以使用
主进程
workerProcess.stdin.write(i + '');
子进程
process.stdin.on('data', function(data){})
fork('./son.js')
相当于 spawn('node', ['./son.js'])
const child_process=require("child_process")
for(var i=0;i<3;i++){
//分别开启新进程去执行index1.js
var workerProcess=child_process.fork('./index1.js',[i])
workerProcess.on('close',(code)=>{
console.log('退出'+code)
})
}
fork的线程通信更简单些
主线程
worker_process.send(i); //send-'message'
子线
process.on('message', function(m){})
先说一下和路径有关的全局变量
//node的全局变量
console.log(__dirname)//目录路径,D:\准备\老陈安排\nodejs基础\demo07
console.log(__filename)//文件路径,D:\准备\老陈安排\nodejs基础\demo07\index1.js
然后看一下path模块的操作
//node的全局变量
console.log(__dirname)//目录路径,D:\准备\老陈安排\nodejs基础\demo07
console.log(__filename)//文件路径,D:\准备\老陈安排\nodejs基础\demo07\index1.js
let path=require('path')
console.log(path.extname('./index1.js'))//获得扩展名,.js
console.log(path.basename(__filename))
console.log(path.basename('D:\\准备\\老陈安排\\nodejs基础\\demo07\\index1.js'))//获得文件名
console.log(path.dirname(__filename))//获取目录名称
console.log(path.normalize('D:/准备/老陈安排\\nodejs基础'))//转化成规范常用写法
console.log(__dirname+'/index1.js',path.join(__dirname,'index1.js'))//路径拼接
console.log(path.resolve('index1.js'))//路径解析
join和resolve的区别就是https://www.cnblogs.com/moqiutao/p/8523955.html
join是单纯的用/
来拼接字符串,resolve则会从工作根目录解析出绝对路径
协议:计算机之间使用协议进行通信,常用的有IP、TCP、HTTP、POP3、SMTP等
协议栈:协议的分层,有两种模型:TCP/IP和OSI
协议的作用:对等层虚拟通信;层次间的无关性
协议的层次间无关性:对等层通信时,只利用较低层次提供的接口和服务,不需要了解底层的协议,层层向下传递;底层也只是使用高层出传来的参数和信息
https://blog.csdn.net/weixin_30363263/article/details/80808231
http:超文本传输协议是属于应用层的基于TCP/CP通信协议的从www服务器传输超文本到本地浏览器的传输协议
请求需要再仔细去看看
let http = require('http')
let server =http.createServer();//创建服务器
server.on('request',(req,res)=>{
console.log(req.url)
res.write(req.url)
res.end()
})
//监听端口
server.listen(8003,()=>{
console.log('启动:','http://localhost:8003')
})
启动之后
然后根据解析req传递的请求就可以对应接口返送不同的数据了
let express=require('express')
let app=express()//实例化服务器
app.use(express.static('./static'))//访问静态资源
app.listen(3002,()=>{//启动监听
console.log('express:','http://127.0.0.1:3002')
})
访问static下静态资源
自定义接口呢
let express=require('express')
let app=express()//实例化服务器
app.use(express.static('./static'))//访问静态资源
//自定义接口
app.get('/hello',(req,res)=>{
res.send('hello')
})
app.get('/list',(req,res)=>{
res.json({
data:[
1,2,3
]
})
})
app.listen(3002,()=>{//启动监听
console.log('express:','http://127.0.0.1:3002')
})