Node.js
1.什么是Node.js
Node.js 是一个基于Chrome V8 引擎得JavaScript运行环境
2.Node.js中得JavaScript运行环境
注:1.浏览器是JavaScript得前端运行环境
2.Node.js是JavaScript得后端运行环境
3.Node.js中无法调用DOM和BOM等浏览器内置API
3.Node.js可以做什么
Node.js 作为一个 JavaScript 的运行环境,仅仅提供了基础的功能和 API。然而,基于 Node.js 提供的这些基础能,很多强大的工具和框架如雨后春笋,层出不穷,所以学会了 Node.js ,可以让前端程序员胜任更多的工作和岗位:
①基于 Express 框架(www.expressjs.com.cn/),可以快速构建 Web 应用
②基于 Electron 框架(electronjs.org/),可以构建跨平台的桌面应用
③基于 restify 框架(restify.com/),可以快速构建 API 接口项目
④读写和操作数据库、创建实用的命令行工具辅助前端开发、etc…
4.Node.js内置模块
4.1-fs 文件系统模块
fs模块是Node.js官方提供的、用来操作文件的模块。它提供了一系列的方法和属性,用来满足用户对文件的操作需求
fs.readFile(path,[options],[callback])
参数1:必选参数,表示文件的路径
参数2:可选参数,表示以什么编码格式来读取文件
参数3:必选参数,文件读取完成后,通过回调函数拿到读取结果
//导入fs模块
const fs =require('fs')
//调用fs.readFile()方法读取文件
fs.readFile('../file/1.text','utf-8',function(err,dataStr){
console.log(err) //null
console.log('-----------------')
console.log(dataStr) //hello world!
})
fs.writeFile(filepath,data,[options],callback)
参数1:必选参数,需要指定一个文件路径字符串,表示文件的存放路径
参数2:必须参数,表示要写入的内容
参数3:可选参数,表示以什么格式写入文件内容,默认值是utf8
参数4:必选参数,文件写入完成后的回调函数
fs.writeFile('../file/2.text','summer','utf8',function(err,dataStr){
if(err){
console.log('文件写入失败')
}
console.log('成功')
})
4.2-path路径模块
path 模块是Node.js官方提供的、用来处理路径的模块。它提供了一系列的方法和属性,用来满足用户对路径的处理需求。
__dirname:获取当前目录路径
const path = require('path')
//拼接路径 __dirname
const filePath = path.join(__dirname,'file/1.text')
console.log(filePath)
//获取完整文件名 basename
const fileName = path.basename(filePath)
console.log(fileName) //1.text
//只获取文件名 basename
const name = path.basename(filePath,'.text')
console.log(name) //1
// 获取文件后缀 extname
const fext = path.extname(filePath)
console.log(fext) //.text
4.3-http模块
http 模块是Node.js官方提供的、用来创建 web 服务器的模块。通过http模块提供的http.createServer() 方法,就能方便的把一台普通的电脑,变成一台Web服务器,从而对外提供Web资源服务。
const http = require('http')
// 创建服务器
const server = http.createServer()
// 绑定事件
server.on('request',function(req,res){
console.log('Hello This My First Server')
// 解决中文乱码
res.setHeader('Content-Type','text/html; charset=utf-8')
res.end("Hello,我是一个服务器")
})
//启动服务端
server.listen(8080,function(){
console.log('Server runing at http://127.0.0.1:8080')
})
5.什么是模块化
模块化是指解决一个复杂问题时,自顶向下逐层把系统划分成若干模块的过程。对于整个系统来说,模块是可组合、分解和更换的单元。
把代码进行模块化拆分的好处:
①提高了代码的复用性
②提高了代码的可维护性
③可以实现按需加载
5.1-模块得分类:
内置模块、自定义模块、第三方模块
5.2-加载模块
//1.加载内置得fs模块
const fs = require('fs')
//2.加载自定义模块
const zdy = require('./zdy.js')
//3.加载第三方模块
const moment = require('moment')
//注:使用 require() 方法加载其它模块时,会执行被加载模块中的代码
5.3-模块作用域
和函数作用域类似,在自定义模块中定义的变量、方法等成员,只能在当前模块内被访问,这种模块级别的访问限制,叫做模块作用域
好处是:防止全局变量污染
5.4-向外共享模块作用域中得成员
在自定义模块中,可以使用 module.exports 对象,将模块内的成员共享出去,供外界使用。
外界用 require() 方法导入自定义模块时,得到的就是 module.exports 所指向的对象。
使用require()方法导入模块时,导入的结果,永远以 module.exports 指向的对象为准。
6.Node.js中模块化规范
Node.js 遵循了 CommonJS 模块化规范,CommonJS 规定了模块的特性和各模块之间如何相互依赖。
CommonJS 规定:
①每个模块内部,module 变量代表当前模块。
②module 变量是一个对象,它的 exports 属性(即 module.exports)是对外的接口。
③加载某个模块,其实是加载该模块的 module.exports 属性。require() 方法用于加载模块。
7.模块的加载机制
7.1-优先从缓存中加载
模块在第一次加载后会被缓存。 这也意味着多次调用 require() 不会导致模块的代码被执行多次。
注意:不论是内置模块、用户自定义模块、还是第三方模块,它们都会优先从缓存中加载,从而提高模块的加载效率
7.2-内置模块的加载机制
内置模块是由 Node.js 官方提供的模块,内置模块的加载优先级最高。
例如,require('fs') 始终返回内置的 fs 模块,即使在 node_modules 目录下有名字相同的包也叫做 fs。
7.3-自定义模块的加载机制
使用 require() 加载自定义模块时,必须指定以 ./ 或 ../ 开头的路径标识符。在加载自定义模块时,如果没有指定 ./ 或 ../ 这样的路径标识符,则 node 会把它当作内置模块或第三方模块进行加载。
同时,在使用 require() 导入自定义模块时,如果省略了文件的扩展名,则 Node.js 会按顺序分别尝试加载以下的文件:
①按照确切的文件名进行加载
②补全 .js 扩展名进行加载
③补全 .json 扩展名进行加载
④补全 .node 扩展名进行加载
⑤加载失败,终端报错
7.4-第三方模块的加载机制
如果传递给 require() 的模块标识符不是一个内置模块,也没有以 ‘./’ 或 ‘../’ 开头,则 Node.js 会从当前模块的父目录开始,尝试从 /node_modules 文件夹中加载第三方模块。
如果没有找到对应的第三方模块,则移动到再上一层父目录中,进行加载,直到文件系统的根目录。
例如,假设在 'C:\Users\summer\project\foo.js' 文件里调用了 require('tools'),则 Node.js 会按以下顺序查找:
C:\Users\summer\project\node_modules\tools
C:\Users\summer\node_modules\tools
C:\Users\node_modules\tools
C:\node_modules\tools
7.5-目录作为模块
当把目录作为模块标识符,传递给 require() 进行加载的时候,有三种加载方式:
①在被加载的目录下查找一个叫做 package.json 的文件,并寻找 main 属性,作为 require() 加载的入口
②如果目录里没有 package.json 文件,或者 main 入口不存在或无法解析,则 Node.js 将会试图加载目录下的 index.js 文件。
③如果以上两步都失败了,则 Node.js 会在终端打印错误消息,报告模块的缺失:Error: Cannot find module 'xxx'
8.Express
8.1-什么是Express
官方给出的概念:Express 是基于 Node.js 平台,快速、开放、极简的 Web 开发框架。
通俗的理解:Express 的作用和 Node.js 内置的 http 模块类似,是专门用来创建 Web 服务器的。
Express 的本质:就是一个 npm 上的第三方包,提供了快速创建 Web 服务器的便捷方法。
8.2-创建基本web服务器
// 导入express
const express = require('express')
// 创建web服务器
const app = express()
//向外共享静态资源
app.use('/abc',express.static('./clock'))
//监听请求
app.get('/login',(req,res)=>{
const per = {name:'zs',age:20}
res.send(per)
//获取?后面的内容
console.log(req.query)
})
//匹配动态参数
app.get('/login/:id',(req,res)=>{
const per = {name:'zs',age:20}
res.send(per)
//获取?后面的内容
console.log(req.params)
})
app.post('/login',(req,res)=>{
res.send('登录成功')
})
//启动服务器
app.listen(8080,()=>{
console.log('start server 127.0.0.1:8080')
})
8.3-托管静态资源
express提供了一个非常好用的函数,叫做express.static(),通过它,我们可以非常方便地创建一个静态资源服务器,例如,通过如下代码就可以将 public目录下的图片、CSS文件、JavaScript文件对外开放访问了:
app.use(express.static('public'))
如果要添加多个静态资源目录,就多次调用该方法,访问静态资源文件时,express.static() 函数会根据目录的添加顺序查找所需的文件。
8.4-Express中的路由
在Express中,路由指的是客户端的请求与服务器处理函数之间的映射关系。
Express中的路由分3部分组成,分别是请求的类型、请求的 URL 地址、处理函数,格式如下:
app.METHOD(PATH,HANDLER)
8.5-模块化路由
为了方便对路由进行模块化的管理,Express 不建议将路由直接挂载到 app 上,而是推荐将路由抽离为单独的模块。
将路由抽离为单独模块的步骤如下:
①创建路由模块对应的 .js 文件
②调用 express.Router() 函数创建路由对象
③向路由对象上挂载具体的路由
④使用 module.exports 向外共享路由对象
⑤使用 app.use() 函数注册路由模块
/*模块化路由*/
const express = require('express')
// 创建路由对象
const router = express.Router()
// 挂在路由
router.get('/',(req,res)=>{
res.send('get')
})
router.post('/',(req,res)=>{
res.send('post')
})
// 向外到处路由对象
module.exports = router
const express = require('express')
// 导入路由模块
const router = require('./10-模块化路由')
const app = express()
// 注册路由模块
// 注意:app.use()函数得作用,就是来注册全局中间件得
app.use(router)
app.listen(8080,()=>{
console.log('start server 127.0.0.1:8080')
})
9.中间件
9.1-什么是中间件
中间件(Middleware),特指业务流程的中间处理环节。
9.2-中间件的调用流程
当一个请求到达 Express的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理
9.3-next函数的作用
next 函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由
9.4-定义中间件函数
const mw = (req,res,next)=>{
console.log('这是一个中间件')
next()
}
9.4.1-全局生效的中间件
const mw = (req,res,next)=>{
console.log('这是一个中间件')
next()
}
//调用 app.use(中间件函数),使mw这个中间件在全局生效
app.use(mw)
//------------------------------------------
//简化写法
app.use((req,res,next)=>{
console.log('这是一个全局中间件')
console.log('用app.use挂在得是全局中间件')
next()
})
9.4.2-局部生效的中间件
不使用 app.use()定义的中间件,叫做局部生效的中间件
const mw1 = (req,res,next)=>{
console.log('这是一个中间件')
next()
}
app.get('/login',mw1,(req,res)=>{
console.log('这是一个普通路由,经过了局部中间件mv1')
console.log('-------------------------')
})
9.5-中间件的作用
多个中间件之间,共享同一份 req 和 res。基于这样的特性,我们可以在上游的中间件中,统一为req或res对象添加自定义的属性或方法,供下游的中间件或路由进行使用。
9.6-中间件的使用注意事项
①一定要在路由之前注册中间件
②客户端发送过来的请求,可以连续调用多个中间件进行处理
③执行完中间件的业务代码之后,不要忘记调用 next() 函数
④为了防止代码逻辑混乱,调用 next() 函数后不要再写额外的代码
⑤连续调用多个中间件时,多个中间件之间,共享 req 和 res 对象
⑥错误级别的中间件一定要放在路由之后
9.7-中间件的分类
① 应用级别的中间件
② 路由级别的中间件
③ 错误级别的中间件
④ Express 内置的中间件
⑤ 第三方的中间件