【博学谷学习记录】超强总结,用心分享|Node.js学习笔记

148 阅读10分钟

Node.js

1.什么是Node.js

Node.js 是一个基于Chrome V8 引擎得JavaScript运行环境

2.Node.js中得JavaScript运行环境

image.png

注: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)    //nullconsole.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的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理

image.png

9.3-next函数的作用

next 函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由

image.png

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 内置的中间件

⑤ 第三方的中间件