Node.js学习
概述
Node.js 是一个基于 Chrome V8 引擎 的 JavaScript 运行时环境,允许在服务器端运行 JavaScript 代码。它采用事件驱动和非阻塞 I/O 模型,适合构建高性能、可扩展的网络应用,尤其擅长处理实时应用和大规模数据密集型场景
背景
-
JavaScript 的普及
JavaScript 最初是浏览器端的脚本语言,但随着 Web 2.0 和 AJAX 技术的兴起,JavaScript 在前端开发中变得至关重要。开发者希望能在服务器端也使用 JavaScript,以实现前后端语言统一,简化开发流程。 -
高性能服务器需求
传统服务器(如 Apache)采用多线程模型处理请求,每个请求占用一个线程,资源消耗大且难以应对高并发。Node.js 通过事件驱动和非阻塞 I/O模型,解决了这一问题,能够高效处理大量并发请求。 -
Chrome V8 引擎的出现
2008 年,Google 发布了 Chrome 浏览器,其 JavaScript 引擎 V8 性能卓越,能够快速编译和执行 JavaScript 代码。Node.js 的创始人 Ryan Dahl 受到启发,利用 V8 引擎构建了一个服务器端运行时环境,使 JavaScript 能够脱离浏览器运行。JavaScript 代码直接编译为机器码,而不是解释执行,从而大幅提升执行速度。 -
事件驱动编程的兴起
事件驱动编程模型在 GUI 和网络编程中广泛应用,Ryan Dahl 认为这种模型非常适合处理高并发的网络请求。Node.js 采用事件循环机制,能够高效处理 I/O 操作,避免线程阻塞。 -
Ryan Dahl 的初衷
Ryan Dahl 在开发 Node.js 时,目标是创建一个轻量级、高效的平台,专注于实时应用和高并发场景。他希望通过非阻塞 I/O 和事件驱动模型,解决传统服务器的性能瓶颈。 -
开源社区的推动
Node.js 于 2009 年开源后,迅速吸引了大量开发者。其轻量级、高性能的特点,加上 JavaScript 的广泛使用,使其在短时间内获得了广泛关注和支持
安装
node.js官网
无BOM和DOM
node,js中顶级对象是globle对象
fs(file system)模块
与硬盘交互
导入fs模块
let fs=require("fs")
写入|追加|文件流式
writeFile|appendFile|createWriteStream
打开文件是需要消耗资源的,文件流式可以减少打开关闭文件的次数,适用于大文件高频次的写入
异步
let fs=require("fs")
fs.writeFile("./testFile.txt","测试file",err=>{if(err){console.log("写入失败")}else{console.log("写入成功")}
})fs.appendFile("./writeFile.txt","asdasd",err=>{if(err){}else{console.log("追加成功")}
})let ws=fs.createWriteStream("./writeFile.txt")
ws.write("阿萨德哈手机侃大山客户卡几哈")
ws.close()
同步
同步无callback函数
writeFileSync|appendFileSync
读取
readFile|readFileSync|createReadStream
let rf=fs.readFile("./writeFile.txt",(err,data)=>{if(err){}else{console.log(data.toString())}
})
// chunk 循环去读,一次只能读一块:65536字节=64KB
rs=fs.createReadStream("writeFile.txt")
rs.on('data',chunk=>{console.log(chunk.toString())
})
// 读取结束
rs.on("end",()=>{console.log("读取完成")
})
读取-写入
let data=fs.readFileSync("./writeFile.txt")
fs.writeFileSync("./writeFileCopy.txt",data)let rs=fs.createReadStream("./writeFile.txt")
let ws=fs.createWriteStream("./writeFileCopyStream.txt")rs.on("data",chunk=>{ws.write(chunk)})rs.on("end",()=>{console.log("读取完成")})
重命名==移动
rename|renameSync
fs.rename("./writeFileCopyStream.txt","./1.txt",rr=>{
})fs.rename("1.txt","./a/11.txt",err=>{console.log(err)
})
删除
unlink|unlinkSync
fs.unlink("./a/11.txt",err=>{if(err){}else{console.log("删除成功")}
})
node.js 14 新增
rm|rmSync
fs.rm("./writeFileCopy.txt",err=>{if(err){}else{console.log("删除成功")}
})
文件夹
创建文件夹
fs.mkdir("a"err=>{
console.log(err)
})
递归创建
fs.mkdir("a/b/c",{recursive:true},err=>{console.log(err)
})
删除文件夹
fs.rmdir("aa",err=>{})
读取文件夹
fs.readdir("img",(err,data)=>{if(!err){console.log(data)}
})
补充: data.isDirectory() :是否文件夹 data.isFile():是否文件
路径问题
fs.writeFile("./aa.txt","adasdsad",err=>{console.log(err)
})
其创建文件以命令行为维度而不是当前文件所在位置为维度
绝对路径
__dirname:获取项目的绝对路径
path 模块
require(“path”)
resolve 路径拼接
console.log(path.resolve(__dirname,"test.html"))
sep 当前操作系统分隔符
console.log(path.sep)
路径解析
console.log(path.parse("C:\\Users\\xsx\\Desktop\\test\\hello.js")){root: 'C:\\',dir: 'C:\\Users\\xsx\\Desktop\\test',base: 'hello.js',ext: '.js',name: 'hello'
}
获取文件名|文件目录 扩展名
let str="C:\\Users\\xsx\\Desktop\\test\\hello.js"
console.log(path.basename(str))
console.log(path.dirname(str))
console.log(path.extname(str))//
hello.js
C:\Users\xsx\Desktop\test
.js
http 模块
http资料
let http=require("http")let server=http.createServer((request,response)=>{response.end("hellt http server")
})
// 设置端口--回调
server.listen(9000,()=>{console.log("server start")
})
request
- request.url
- request.method
- request.headers:返回对象
获取参数-post
// 声明一个变量let body=""// 绑定data 事件request.on("data",chunk=>{body+=chunk})// 绑定 end 事件request.on("end",()=>{console.log(body)console.log("request end")})
url 模块
let url=require("url")
获取参数
get
let url=require("url")let server=http.createServer((request,response)=>{console.log(request.method)let urlParse=url.parse(request.url)console.log(urlParse)
//
Url {protocol: null,slashes: null,auth: null,host: null,port: null,hostname: null,hash: null,search: '?name=sux&age=11',query: 'name=sux&age=11',pathname: '/search',path: '/search?name=sux&age=11',href: '/search?name=sux&age=11'
}})
// 设置端口--回调
server.listen(9000,()=>{console.log("server start")
})
response
- 设置状态码:response.statusCode
- 设置响应头: response.setHeader(key,value)
response.setHeader("content-type","application/json")`在这里插入代码片`
- 设置响应体: response.write(),response.end()
write可以有多个,但最后以唯一一个end()结束,或者直接end(value)
资源类型(MIME)
媒体类型(mime类型)是一种标准,用来表示文档、文件或字节流的性质和格式
HTTP服务可以设置响应头Content-Type来表面响应体的MIME类型,浏览器会根据类型去如何处理资源
- html :text/html
- css: text/css
- js:text/javascript
- png:image/png
- jpg:image/jpeg
- gif:image/gif
- mp4:video/mp4
- mp3:audio/mpeg
- json:application/json
对于未知资源类型:applicaton/octet-stream类型,浏览器遇到该类型时会对响应体内容进行独立存储,也就是我们常见的下载
模块(CommonJS)
导出:exports
核心:exports=module.exports={} 是一个对象
exports.name=value
module.exports 是 CommonJS 模块系统的默认导出对象。
module.exports="asdasdasdasd"module.exports={testModule,testModule2}
导入:require
const module1=require("./module1.js")
- 导入时的路径写相对路径,且不能省略 ./或…/
- 导入可以省略js或json后缀名
- 如果导入的是文件夹,则首先会检测文件夹下package.json的main属性对应的文件。如果存在,则导入。如果不存在package或者main则或导入其文件夹下index.js或index.json。否则报错。
注:js或json同时存在同名,则只会导入js - 导入node.js内置模块是,可直接require模块名字
包管理工具
- npm
- yarn
- cnpm
npm (node package manager)
npm 是node.js官方内置的包管理工具,在node.js会默认安装npm
查看版本
初始化包
注: npm init -y 或 npm init --yes 会默认快速创建
搜索包
- 命令行
npm s/search 关键字
- 去网站搜索 https:// www.npmjs.com
安装
npm i/install :根据package.json和package-locjk.json的依赖声明安装整个项目依赖
npm i/install <报名>// npm install uniq
npm 安装指定版本的包
npm i <包名@版本号>
npm 删除包
npm r/remove <包名>
// 全局删除
nppm r/remove -g <包名>
运行之后文件夹下会产生两个资源
- node_modules 用来存放下载的包
- package-lock 包的锁定文件,用来锁定包版本
引入
const uniq=require("uniq")const arrp=[1,2,3,4,5,5,5,5]
uniq(arrp)
require导入npm包的基本流程
在当前文件下node_modules下去寻找,未找到会到上级目录的node_modules去寻找,直至到磁盘根目录。
生成、开发、全局版本
- npm i -S 默认
- npm i -D
- npm i -g
nodemon: 自动重启node程序
npm root -g: 全局包的安装位置
配置命令别名
通过配置命令别名可以更简单的执行命令
配置package.json的script属性
"scripts": {"test": "echo \"Error: no test specified\" && exit 1","dev":"node test.js"},
npm run dev
npm 配置淘宝镜像
npm config set registry https://registry npmmirror.com/
cnpm(了解)
cnpm是淘宝构建构建的npmjs,con的完整镜像,也称淘宝镜像,网址https://npmmirror.com/
cnpm服务部署在国内阿里云服务器上,可以调高包的下载速度。
淘宝镜像为只读与官方同步频率为10分钟一次
安装
通过npm命令去安装cnpm
npm install -g cnpm --register=https://npmmirror.com/
cnpm与npm使用命令相同
NVM (node version manager)
解决:多个node.js版本的下载、切换
- nvm list available 显示所有可以下载的node.js版本
- nvm list 显示已安装的node.js版本
- nvm install <版本号> 安装
- nvm user <版本号> 使用
Express
express是一个基于node.js平台极简、灵活的WEB应用开发框架。官网地址:https://erpressjs.com.cn/
安装
npm intall express
创建
const express=require("express")// 创建请求应用
let app=express()
// 创建路由请求
app.get("/home",(req,res)=>{res.setHeader("content-type","text/html;charset=utf-8")res.write("阿萨德哈健康会尽快")res.end()
})
// 监听端口,启动服务
app.listen(9000,()=>{console.log("启动正常")
})
路由
官网定义:路由确定了应用程序如何响应客户端对特定端点的请求
路由的组成
一个路由的组成有请求方法、路径和回调函数
格式:
app.<method>(路径,回调函数)
method:
- get
- post
- all
request
- request.method
- request.url
- request.pathname
- request.ip
- request.headers
- request.get(name) :获取请求头中指定的name
- requset.query:参数
路由参数
占位符 :id
// 请求路径:http://127.0.0.1:9000/9999.htmlapp.get("/:id.html",(req,res)=>{console.log(req.params.id) // 9999})
reseponse
express 中间件(类似java–filter)
介绍
中间件本质上是一个函数
作用
中间件的作用就是使用函数封装的公共操作,简化代码。
类型
- 全局中间件
- 路由中间件
全局中间件
全局配置
const express= require("express")
const fs=require("fs")
const path=require("path")
// 创建
function recordMiddleware(req,res,next){let {url,ip}=reqconsole.log(__dirname)fs.appendFileSync(path.resolve(__dirname,"./ip.txt"),`${url}--${ip}\r\n`)// 继续往下执行next()
}const app=express()
// 加载配置使用
app.use(recordMiddleware)
app.get("/get",(req,res)=>{res.send("success")
})app.listen(9000,()=>{console.log("启动成功")
})
路由中间件
路由配置
let routeMiddleware=(req,res,next)=>{if(req.query.code=="xusx"){next()}else{res.send("fail")}
}const app=express()
// app.use(recordMiddleware)
app.get("/get",routeMiddleware,(req,res)=>{res.send("success")
})app.listen(9000,()=>{console.log("启动成功")
})
express内置静态资源中间件
根据request.path去静态目录下查找然后直接输出
const app=express()
app.use(express.static(__dirname+"/public"))
文件目录
注:当请求路径为"/"时,会自动去目录下搜寻默认的index.html
获取post请求体-post入参
body-parser
const bodyParser=require("body-parser")// 请求体为json
const jsonParse=bodyParser.json()
// 请求体为form
const urlencodedParse=bodyParser.urlencoded({extended:false})
// 添加局部中间件
app.post("/postInfo",urlencodedParse,(req,res)=>{console.log(req.body)console.log(req.body.age)
})
路由模块化
express.Router()
app.use()
getRoute.js
const express=require("express")const getRouter=express.Router()getRouter.get("/getIndex",(req,res)=>{res.send("asdasd")
})module.exports= getRouter
const getRouter=require("./router/getRouter")
const app=express()app.use(getRouter)
// 可添加路由前缀
// app.use("/testGet",getRouter)
app.listen(9000,()=>{console.log("启动成功")
})
模板引擎-ejs
变量
格式:<%= %>const ejs=require("ejs")const str1="学习"
let result=ejs.render(`早上开始<%= str1%>`,{str1:str1})
代码
格式:<% %>
const ejs=require("ejs")
const isLogin=false
let result=ejs.render(`<% if(isLogin){ %><p>成功</p><% }else{%><p>失败</p><% }%>`,{isLogin:isLogin})
express 中使用ejs
const express=require("express")
const isLogin=true// 创建路由
const app=express()
// 设置所使用的模板引擎
app.set("view engine","ejs")
// 设置模板所在的目录
app.set("views",__dirname)app.get("/home",(req,res)=>{// 输出res.render('home',{isLogin})
})
app.listen(9000,()=>{console.log("启动成功")
})
home.ejs 后缀名ejs
<!DOCTYPE html>
<html><body><% if(isLogin){ %><p>成功</p><% }else{%><p>失败</p><% }%></body>
</html>
express-generator
是一个用于快速生成 Express.js 应用骨架的命令行工具。通过它,你可以轻松创建一个包含基本目录结构和文件的 Express 项目,从而节省手动配置的时间。
主要功能
-
生成项目结构:自动创建标准的 Express 应用目录,如 routes、views、public 等。
-
设置基本路由:生成默认的路由文件,帮助你快速开始开发。
-
配置模板引擎:支持多种模板引擎(如 EJS、Pug、Handlebars),并自动配置。
-
提供静态文件支持:自动设置 public 目录用于存放静态资源。
安装
npm install -g express-generator
使用
express [文件名]