*
1. 文件
1.1. 文件的读取与写入
-
// 1.使用rquire方法加载fs(fileststem)核心模块 let fs = require('fs'); // 2.读取文件 fs.readFile('./data/hello.txt', function(error, data) { if(error) { console.log("文件读取失败!") } else { console.log(data.toString()); } }); // 第一个参数:文件路径 第二个参数:文件内容 第三个参数是回调函数 fs.writeFile('./data/你号.txt.txt', 'node.js号啊', function(error) { if(error) { console.log("文件写入失败!" + error); } else { console.log("文件写入成功!"); } })
1.2. 文件流
-
文件写入流
let fs = require('fs') // 创建写入流 // 语法:fs.createWriteStream(文件路径, [可选的配置操作]) let ws = fs.createWriteStream('hello.txt', {flags: 'w', encoding: 'utf-8'}) // 监听文件打开事件 ws.on('open', () => { console.log('1. 文件打开了') }) // 监听准备事件 ws.on('ready', () => { console.log('2. 文件写入已进入准备状态') }) // 监听文件关闭事件 ws.on('close', () => { console.log('5. 文件完成, 关闭') }) ws.write('1. hello world给\n', (err) => { if (err) { return console.log(err) } console.log('3. 内容1流入完成!') }) ws.write('2. hello world给', (err) => { if (err) { return console.log(err) } console.log('3. 内容2流入完成!') }) // 文件写入完成 ws.end(() => console.log('4. 文件写入关闭!'))
-
文件输入流 (将读取的数据写入到新文件中)
let fs = require('fs') // 创建读取流 // 语法;fs.createReadStream(路径, [可选配置项]) // let rs = fs.createReadStream('../1.mp4', {flags: 'r', encoding: 'utf-8}) // 以二进制的形式读取视频 let rs = fs.createReadStream('../1.mp4', {flags: 'r'}) let ws = fs.createWriteStream('./2.mp4', {flags: 'w'}) // 监听流的打开 rs.on('open', () => console.log('读取文件打开!')) // 监听流的关闭 rs.on('close', () => { console.log('读取流结束!') // 当读取流完毕后再关闭写入流 ws.end() }) // 每一批次数据流入的完成 rs.on('data', (chunk) => { console.log(chunk) ws.write(chunk, () => console.log('单批数据流入完成')) // console.log('每一次读取的长度' + chunk.length) })
-
管道流 (高度封装的一个方法 读取写入速度很快)
let fs = require('fs') let rs = fs.createReadStream('../1.mp4', {flags: 'r'}) let ws = fs.createWriteStream('./3.mp4', {flags: 'w'}) // 监听流的打开 rs.on('open', () => console.log('读取文件打开!')) // 监听流的关闭 rs.on('close', () => console.log('close!')) // rs.pipe(ws) 高度封装的将读取的数据写入到新的文件中 // 速度很快 rs.pipe(ws)
*
2. HTTP
2.1 HTTP. 使用案例
// 加载http核心模块
let http = require('http')
// 使用http.createServer() 方法创建一个Web服务器 返回一个Server实例
let server = http.createServer()
// 绑定端口号 启动服务器
server.listen(9919, function() {
console.log('服务器启动成功了... 通过 http://localhost:9919/ 来访问吧')
});
server.on('request', function(request, response) {
console.log('收到客户端的请求了... 请求的路径是' + request.url)
response.write('hello')
response.write('nodejs简介')
// 告诉客户端 输完了
response.end();
})
2.2. 表单同步提交和异步提交
-
表单具有默认的提交行为,默认是同
-
步的,同步表单提交,浏览器会锁死(转圈儿)等待服务端的响应结果。
-
表单的同步提交之后,无论服务端响应的是什么,都会直接把响应的结果覆盖掉当前页面。
-
阻止浏览器的默认提交行为示例代码
-
// 异步提交 $('#register_form').on('submit', function (e) { e.preventDefault() var formData = $(this).serialize() $.ajax({ url: '/register', type: 'post', data: formData, dataType: 'json', success: function (data) { let error_code = data.error_code if (error_code === 0) { window.alert('注册成功!') } else if (error_code === 1) { window.alert('邮箱已存在!') } else if(error_code === 2) { window.alert('用户名已存在!') } else if(error_code === 500) { window.alert('服务器忙, 请稍后重试!') } } }) })
2.3. 服务端重定向针对异步请求无效
-
服务器重定向只能针对同步请求有效,针对异步请求无效
-
只能客户端自己跳转
*
3. npm 常用命令
-
npx http-server
- 开启一个服务
// //开一个端口为 9000 的服务 npx http-server -p 9000
- npm init
- npm init -y 可以跳过向导,快速生成
-
**npm install **
- 一次性把dependencies 选项中的依赖全部安装
-
npm install 包名
- 只下载
-
npm install --save 包名
- 下载并且保存依赖项(package.json 文件中的dependencies 选项)
- 可以简写成 npm i -S 包名
- npm uninstall 包名
- 只删除,如果有依赖项会依赖保存 可以简写成 npm un 包名
- npm uninstall --save 包名
- 删除的同时也会把依赖信息也去除 可简写成 npm un -S 包名
- **npm help **
- 查看使用帮助
- npm 命令 --help
- 查看指定命令的使用帮助 例如忘记uninstall 命令的简写了,这个时候可以通过 npm uninstall --help 来查看使用帮助
- 解决npm被墙问题
- 下载淘宝镜像 通过cnpm 来下载插件和库包 通过命令: npm install -g cnpm --registry=https://registry.npm.taobao.org 或者: npm install --global cnpm
3.1. Node 相关工具
-
// 这样设置可以使用 npm 的方式进行下载 npm config set registry https://registry.npm.taobao.org // 可以查看 npm 怕配置信息 npm config list
-
Windows 安装 nvm
- nvm-windows
- nodist
-
nvm for windows是一个命令行工具,在控制台输入nvm,就可以看到它的命令用法。基本命令有:
- nvm arch [32|64] : 显示node是运行在32位还是64位模式。指定32或64来覆盖默认体系结构。
- nvm install [arch]: 该可以是node.js版本或最新稳定版本latest。(可选[arch])指定安装32位或64位版本(默认为系统arch)。设置[arch]为all以安装32和64位版本。在命令后面添加–insecure ,可以绕过远端下载服务器的SSL验证。
- nvm list [available]: 列出已经安装的node.js版本。可选的available,显示可下载版本的部分列表。这个命令可以简写为nvm ls [available]。
- nvm on: 启用node.js版本管理。
- nvm off: 禁用node.js版本管理(不卸载任何东西)
- nvm proxy [url]: 设置用于下载的代理。留[url]空白,以查看当前的代理。设置[url]为none删除代理。
- nvm node_mirror [url]:设置node镜像,默认为https://nodejs.org/dist/.。我建议设置为淘宝的镜像https://npm.taobao.org/mirrors/node/
- nvm npm_mirror [url]:设置npm镜像,默认为https://github.com/npm/npm/archive/。我建议设置为淘宝的镜像https://npm.taobao.org/mirrors/npm/
- nvm uninstall : 卸载指定版本的nodejs。
- nvm use [version] [arch]: 切换到使用指定的nodejs版本。可以指定32/64位[arch]。nvm use 将继续使用所选版本,但根据提供的值切换到32/64位模式的
- nvm root [path]: 设置 nvm 存储node.js不同版本的目录 ,如果未设置,将使用当前目录。
- nvm version: 显示当前运行的nvm版本,可以简写为nvm v
nvm list //查看目前已经安装的版本 nvm list available //显示可下载版本的部分列表 nvm install 10.15.0 //安装指定的版本的nodejs nvm use 10.15.0 //使用指定版本的nodejs
*
4. Express
安装:npm i --save express
4.1. 初步express
let express = require('express') // 引入express
// 创建服务器应用程序
let app = express();
// 公开指定目录 可以直接通过public/...方式访问 public 目录下面的资源
app.use('/public/', express.static('./public/')) // 公开资源目录 public 下面的
app.use('/static/', express.static('./static')) // 公开资源目录 static 下面的
app.get('/', function (req, res) {
res.send('hello express!')
})
app.get('/about', function (req, res) {
res.send('hello 你好啊?')
})
// 相当于 server.listen()
app.listen(9919, function() {
console.log('running...')
})
*
修改代码后自动重启服务器
-
nodemon 是一个基于Node.js开发的一个第三方命令行工具 使用时需要独立安装
npm i --global nodemon // 在任意目录执行都行 // 安装完毕后 使用 nodemon app.js // 只要通过nodemon app.js/app 启动服务器,则会监听文件的变化,变化时会自动重启服务器
- 路由
-
在express使用art-templat
npm i -S art-template // 安装 npm i -S express-art-template
-
2. 配置
let express = require('express') let app = express() // 第一个参数表示当渲染以 .art 结尾的文件的时候 使用art-template 模板引擎 // express-art-template 是专门用来在Express 中把art-template 整合到Express中 // 原因就是express-art-template 依赖于art-template *****app.engine('html', require('express-art-template')) // 核心配置 第一个参数是模板引擎的后缀名 // *****如果要修改默认的views 目录 则可以 // app.set('views', 'render 函数的默认路径') // 如 将默认views 修改成 public app.set('views', 'public') // Express 为Response 相应对象提供了一个方法:render // render 方法默认是不能使用 但配置了模板引擎就可以使用了 // res.render('html模板名', {模板数据}) // 第一个参数不能写路径,默认会去views 目录查找改模板文件 // *****就是说Express 有一个约定:开发人员把所有视图文件都放在 views 目录中 app.use('/public/', express.static('./public/')) // 公开public下面的资源 app.get('/', function (req, res) { res.render('404.html', { title: '你好?' }) }) app.listen(9919, function () { console.log('running...') })
-
-
用express写留言本
let express = require('express') let app = express() let comments = [] // 第一个参数表示当渲染以 .art 结尾的文件的时候 使用art-template 模板引擎 // express-art-template 是专门用来在Express 中把art-template 整合到Express中 // 原因就是express-art-template 依赖于art-template app.engine('html', require('express-art-template')) // 如果要修改默认的views 目录 则可以 // app.set('views', 'render 函数的默认路径') // 如 将默认views 修改成 public app.set('views', 'public') // Express 为Response 相应对象提供了一个方法:render // render 方法默认是不能使用 但配置了模板引擎就可以使用了 // res.render('html模板名', {模板数据}) // 第一个参数不能写路径,默认会去views 目录查找改模板文件 // 就是说Express 有一个约定:开发人员把所有视图文件都放在 views 目录中 app.use('/public/', express.static('./public/')) app.get('/', function (req, res) { res.render('index.html', { comments: comments }) }) app.get('/post', function (req, res) { res.render('post.html') }) app.get('/pinglun', function (req, res) { let comment = req.query let date = new Date(); comment.dateTime = `${date.getFullYear()}/${date.getMonth()+1}/${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}` comments.push(comment) // res.statusCode = 302 老方法 // res.setHeader('Location', '/') res.redirect('/') }) app.listen(9919, function () { console.log('running...') })
-
throw err
-
抛出异常
-
1、阻止程序的执行
-
把错误的消息打印到控制台
-
-
4.2. 在Express 获取表单POST请求体数据
- 在express 中没有内置获取表单POST请求体的API , 需要使用第三方包:
[body-parser]
。 - 使用GET 获取数据 只需 req.query就ok
npm i -S body-parser
// 配置
let express = require('express')
***let bodyParser = require('body-parser')
let app = express()
// 加入配置后 请求对象上会多出来一个属性 :body 可以通过req.body 来获取POST 请求数据
***app.use(bodyParser.urlencoded({extended: false}))
***app.use(bodyParser.json())
// 使用req.body
app.use(function(req, res) {
let comment = req.body // 通过req.body 来获取 POST请求数据
})
// 解决异步获取不到数据的方法 ====》 使用回调函数
// 获取异步操作的结果
function fn (callback) {
setTimeout(function () {
let data = 'hello'
callback(data)
}, 1000)
}
fn(function (data) {
console.log(data)
})
4.6. 解析 get 提交的链接
let url = require('url')
let objUrl = url.parse('请求的地址')
4.3. 完整案例
4.3.1. app.js
// app.js 启动服务 做一些服务相关的配置 模板引擎
// body-parser 解析表单POST 请求体 提供静态资源服务
// 挂载路由 监听端口启动服务
let express = require('express')
let bodyParser = require('body-parser')
// 导入自己写的 router.js 文件
let router = require('./router')
let app = express()
// 配置模板引擎
app.engine('html', require('express-art-template'))
// 允许访问以/node_modules/ 和 /public/开头的静态资源
app.use('/node_modules/', express.static('./node_modules/'))
app.use('/public/', express.static('./public/'))
// 配置body-parser 解析器
app.use(bodyParser.urlencoded({extended: false}))
app.use(bodyParser.json())
// router(app)
// 把路由容器挂载到 app 服务中
app.use(router)
app.listen(9919, function () {
console.log('running')
})
module.exports = app
4.3.2. router.js
// router.js 路由模块 处理路由 根据不同的请求方法 设置具体的路径
// 模块职责要单一 不能混用 目的:为了增强项目代码可维护性
let fs = require('fs')
let Student = require('./students')
// Express 提供了一种更好的方式 专门用来包装路由的
let express = require('express')
// 创建一个路由容器
let router = express.Router()
// 将路由都挂载到router 路由容器中
router.get('/', function (req, res) {
// 第二个参数是可选项 可以指定编码
// fs.readFile('./db.json', 'utf8', function (err, data) {
// if (err) {
// return res.status(500).send('Server error.')
// }
// })
Student.find(function (err, students) {
if(err) {
return res.status(500).send('Server error.')
}
res.render('index.html', {
// 从文件读取到的数据一定是字符串 需要通过 JSON.parse() 解析
students: students
})
})
})
router.post('/students/new', function (req, res) {
// 获取表单数据 并将数据存入文件中 在读取文件显示到页面中
let student = req.body
Student.save(student, function (err) {
if (err) {
return res.status(500).send('Server error. 保存routerr.js中35行出错' )
}
console.log('保存新用户成功了...')
res.redirect('/')
})
})
router.get('/students/delete', function (req, res) {
let id = req.query.id
Student.delete(id, function (err) {
if (err) {
return res.status(500).send('Server error. 删除中出错routerr.js中47行出错' )
}
console.log(`id为:${id}成了`)
res.redirect('/')
})
})
router.get('/students/new', function (req, res) {
// 获取表单数据
res.render('new.html')
})
router.get('/students/edit', function (req, res) {
let id = req.query.id
Student.findById(id, function (err, student) {
if (err) {
return res.status(500).send('Server error. 根据id查找中出错routerr.js中62行出错' )
}
res.render('edit.html', {
student: student
})
})
})
router.post('/students/edit', function (req, res) {
let student = req.body
Student.updateById(student, function (err) {
if (err) {
return res.status(500).send('Server error. 保存routerr.js中35行出错' )
}
console.log('修改新用户成功了...')
res.redirect('/')
})
})
// 把router 导出
module.exports = router
// 原始的包装路由
/* module.exports = function (app) {
app.get('/', function (req, res) {
// 第二个参数是可选项 可以指定编码
fs.readFile('./db.json', 'utf8', function (err, data) {
if (err) {
return res.status(500).send('Server error.')
}
res.render('index.html', {
// 从文件读取到的数据一定是字符串 需要通过 JSON.parse() 解析
students: JSON.parse(data).students
})
})
})
} */
4.3.3. student.js 处理数据代码
// student.js 数据操作文件模块
// 操作文件中的数据 只处理数据 不关心业务
// 导入文件模块
let fs = require('fs')
let dbPath = './db.json'
let student = []
// 获取所有学生
// callback 中的参数
// 第一个是 err 成功是null 错误是错误对象
// 第二个参数是结果 成功是 数组 错误是undefined
exports.find = function (callback) {
fs.readFile(dbPath, 'utf8', function (err, data) {
if (err) {
return callback(err)
}
callback(null, JSON.parse(data).students)
})
}
// 添加学生
exports.save = function (student, callback) {
fs.readFile(dbPath, 'utf8', function (err, data) {
if (err) {
return callback(err)
}
let students = JSON.parse(data).students
// 处理id 问题
if (students.length === 0) {
student.id = 0
} else {
student.id = students[students.length-1].id + 1
}
// 将新数据放入students数组中
students.push(student)
// 将学生数据重新转成字符串
let fileData = JSON.stringify({
students: students
})
// 重新将数据写入文件中
fs.writeFile(dbPath, fileData, function (err) {
if (err) {
// 将错误对象传回去
return callback(err)
}
// 成功就没有错误 所以 null
callback(null)
})
})
}
// 更新学生
exports.updateById = function (student, callback) {
fs.readFile(dbPath, 'utf8', function (err, data) {
if (err) {
return callback(err)
}
let students = JSON.parse(data).students
// 根据id 修改 ES6中的方法 find stu 是修改的对象
let stu = students.find(item => item.id === parseInt(student.id)) // 短路操作查找
console.log(stu)
for (let i in student) {
if (student[i] !== '') {
if (i === 'id') {
stu[i] = parseInt(student[i])
} else {
stu[i] = student[i]
}
}
}
let fileData = JSON.stringify({
students: students
})
fs.writeFile(dbPath, fileData, function (err) {
if (err) {
return callback(err)
}
callback(null)
})
})
}
exports.findById = function (id, callback) {
fs.readFile(dbPath, 'utf8', function (err, data) {
if (err) {
return callback(err)
}
let students = JSON.parse(data).students
let stu = students.find(item => item.id === parseInt(id))
callback(null, stu)
})
}
// 删除学生
exports.delete = function (id, callback) {
fs.readFile(dbPath, 'utf8', function (err, data) {
if (err) {
return callback(err)
}
let students = JSON.parse(data).students
// *****findIndex 方法专门用来***根据条件查找元素的下标
let index = students.findIndex(item => item.id === parseInt(id))
// let index = students.remove(id)
// *****splice 方法 splice(index, 1) 注:两个形参 用来删除 从第几个位置删除 删除几个
students.splice(index, 1)
let fileData = JSON.stringify({
students: students
})
fs.writeFile(dbPath, fileData, function (err) {
if (err) {
return callback(err)
}
callback(null)
})
})
}
// 扩展数组方法 根据id 查找当前的记录
/* Array.prototype.remove = function(value) {
for (let i = 0; i < this.length; i++) {
if(this[i].id === parseInt(value)) {
return i
}
console.log(this[i].id)
}
return -1
} */
4.4. 使用原生js回调函数简单封装ajax中的get方法
function get (url) {
let xhr = new XMLHttpRequest()
// 当请求加载成功之后要调用指定的函数
xhr.onload = function (callback) {
callback(xhr.responseText)
}
xhr.open('get', url , true)
xhr.send()
}
get('./data.json', function(data) {
console.log(data)
})
-
在浏览器中也可以像在 Node 中的模块一样来进行编程
通过
<script>
标签来引用加载,而且必须考虑加载的顺序问题require.js 第三方库 AMD
sea.js 第三方库 CMD
4.5. ES6中find 方法底层代码
// 为Array 扩展方法
Array.prototype.myfind = function (callback) {
for (let i = 0; i < this.length; i++) {
if(callback(this[i], i)) {
return this[i]
}
}
}
// 使用自定义find
let ret = users.myfind((item, index) => {
return item.id === 2
})
*
5. MongoDB
5.1. 关系型数据库和非关系型数据库
-
表就是关系 或者说表与表之间的关系
-
非关系型数据库非常灵活
-
有的非关系型数据库就是 key-value 结构
-
MongoDB 数据库是长的最像关系型数据库的
-
启动(打开两个dos界面先后敲
1
和2
:mongodb :1、mongod4 然后输入: 2、mongo 会默认启动本地数据库
-
如果要修改默认的数据存储目录:mongod --dbpath 数据存储目录路径
-
停止:Ctrl + C
5.2. 基本命令
-
show dbs
- 查看数据库列表
-
db
- 查看当前操作的数据库
-
use 数据库名称
- 切换到指定的数据(如果没有会新建)
-
插入数据
use student
db.student.insertOne({“name”:“Jack”})
db.student.find() 查找student集合
-
show collections => 查询所有集合
-
db.collection名称.drop() 删除集合
-
db.dropDatabase() 删除数据库
5.3. 在Node 中如何操作 MongoDB 数据库
-
使用第三方 mongodb 来操作 MongoDB 数据库
- 第三方包:
mongoose
基于MongoDB 官方的mongodb
包再一次做了封装。
- 第三方包:
-
查询所有
User.find((err, ret) => { if (err) { return console.log(err) } else { console.log(ret) } })
-
根据条件查询所有
User.find({ // 根据条件查询 查询到的数据放到数组中 username: 'Bright', password: '123456' }, (err, ret) => { if (err) { return console.log(err) } else { console.log(ret) } })
-
根据条件查询一个
User.findOne({ // 根据条件查询满足条件的一个 查询到的数据放到数组中 username: 'Bright' }, (err, ret) => { if (err) { return console.log(err) } else { console.log(ret) } })
-
删除数据
Use deleteOne, deleteMany, or bulkWrite.
-
更新
findOneAndUpdate()` findByIdAndUpdate and `findOneAndDelete()
5.4. mongodb 操作crud-express
- students.js 文件(连接mongodb 和 设计schema 以及导出model 以供 router.js使用
let mongoose = require('mongoose')
mongoose.connect('mongodb://localhost:27017/test', {
useNewUrlParser: true,
useUnifiedTopology: true
})
let Schema = mongoose.Schema
let studentSchema = new Schema({
name: {
type: String,
required: true
},
gender: {
type: Number,
enum: [0, 1],
default: 0
},
age: {
type: Number,
},
hobbies: {
type: String,
}
})
//直接导出模型构造函数
module.exports = mongoose.model('Student', studentSchema)
- router.js 文件 路径模块
// router.js 路由模块 处理路由 根据不同的请求方法 设置具体的路径
// 模块职责要单一 不能混用 目的:为了增强项目代码可维护性
let Student = require('./students')
// Express 提供了一种更好的方式 专门用来包装路由的
let express = require('express')
// 创建一个路由容器
let router = express.Router()
// 将路由都挂载到router 路由容器中
router.get('/', function (req, res) {
// 第二个参数是可选项 可以指定编码
// fs.readFile('./db.json', 'utf8', function (err, data) {
// if (err) {
// return res.status(500).send('Server error.')
// }
// })
Student.find(function (err, students) {
if(err) {
return res.status(500).send('Server error.')
}
res.render('index.html', {
// 从文件读取到的数据一定是字符串 需要通过 JSON.parse() 解析
students: students
})
})
})
router.post('/students/new', function (req, res) {
// 获取表单数据 并将数据存入文件中 在读取文件显示到页面中
let student = req.body
new Student(student).save(function (err) {
if (err) {
return res.status(500).send('Server error. 保存routerr.js中35行出错' )
}
console.log('保存新用户成功了...')
res.redirect('/')
})
/* Student.save(student, function (err) {
if (err) {
return res.status(500).send('Server error. 保存routerr.js中35行出错' )
}
console.log('保存新用户成功了...')
res.redirect('/')
}) */
})
router.get('/students/delete', function (req, res) {
let id = req.query.id.replace(/"/g, '')
Student.findByIdAndDelete(id, function (err) {
if (err) {
return res.status(500).send('Server error. 删除中出错routerr.js中47行出错' )
}
console.log(`id为:${id}成了`)
res.redirect('/')
})
})
router.get('/students/new', function (req, res) {
// 获取表单数据
res.render('new.html')
})
router.get('/students/edit', function (req, res) {
let id = req.query.id.replace(/"/g, '')
Student.findById(id, function (err, student) {
if (err) {
return res.status(500).send('Server error. 根据id查找中出错routerr.js中62行出错' )
}
res.render('edit.html', {
student: student
})
})
})
router.post('/students/edit', function (req, res) {
let student = req.body
Student.findByIdAndUpdate(student.id.replace(/"/g, ''), student, function (err) {
if (err) {
return res.status(500).send('Server error. 保存routerr.js中35行出错' )
}
console.log('修改新用户成功了...')
res.redirect('/')
})
})
// 把router 导出
module.exports = router
*
6. 使用Node 操作MySQL数据库
- 安装
cnpm i -S mysql
- 示例代码
let mysql = require('mysql')
// 创建连接
let connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'AI123456',
database: 'yyy'
})
// 连接数据库
connection.connect(function(err) {
if (err) {
console.log('链接失败!')
} else {
console.log('链接成功!')
}
})
// 执行数据操作
connection.query('SELECT * FROM `students`', (err, results, fields) => {
if(err) throw err
console.log(results)
})
// 关闭连接
connection.end()
*
7. Promise
-
callback 回调地狱
- 嵌套 callback
-
为了解决回调地狱嵌套 ES6新增 Promise API
-
Promise 容器中 存放了一个异步任务 但是内部都是封装一个异步任务
- 有三种状态: Pending Resolved =》成功了 Rejected =》 失败了
-
**Promise 使用 案例 **
let fs = require('fs') // ES6 中新增一个API Promise // Promise 是一个构造函数 // console.log(1) // 创建 Promise 容器 // 给别人一个承诺 I promise you // Promise 容器一旦创建 就开始执行里面的代码 let p1 = new Promise(function (resolve, reject) { // console.log(2) fs.readFile('./a.txt', 'utf8', (err, data) => { if (err) { // 失败了,承诺容器中的任务失败了 // 把容器的 Pedding 状态改为 Rejected // 调用 reject 就相当于调用了 then 方法的第二个参数函数 reject(err) } else { // console.log(3) // 承诺容器中的任务成功了 // console.log(data) // 把容器中的 Pedding 状态改为成功, Resolved // 这里调用的 resolve 方法实际上就是 then 方法传递的那个 function resolve(data) } }) }) let p2 = new Promise(function (resolve, reject) { fs.readFile('./b.txt', 'utf8', (err, data) => { if (err) { reject(err) } else { resolve(data) } }) }) let p3 = new Promise(function (resolve, reject) { fs.readFile('./c.txt', 'utf8', (err, data) => { if (err) { reject(err) } else { resolve(data) } }) }) // p1 是那个承诺的实例 // 当p1 成功了 然后(then)做指定的操作 // then方法接收的就是 resolve 函数 相当于调用 resolve 方法就是调then里面的 // 可以 then 到底 上面的 return 作为下面新的 then p1.then((data) => { console.log(data) // 先执行 // return 了一个 Promise 对象的时候 后面的 then 中的方法就是第一个参数 p2 return p2 }, (err) => { console.log('读取文件失败', err) }).then((data) => { // p2 读取到的数据 console.log(data) return p3 }, (err) => { console.log(err) }).then((data) => { console.log(data) }, (err) => { console.log(err) }) // console.log(4)
-
**使用 Promise 封装 fs **
let fs = require('fs')
const { fileURLToPath } = require('url')
// Promise 版本的封装读取文件
function pReadFile (FilePath) {
// return 一个 Promise 对象 调用此方法时直接 then 就 ok
return new Promise(function (resolve, reject) {
fs.readFile(FilePath, 'utf8', (err, data) => {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})
}
// 一直 then 就可以按顺序读取 a.txt b.txt c.txt
pReadFile('./a.txt').then((data) => {
console.log(data)
return pReadFile('./b.txt')
}, (err) => {
console.log(err)
}).then((data) => {
console.log(data)
return pReadFile('./c.txt')
}, (err) => {
console.log(err)
}).then((data) => {
console.log(data)
}, (err) => {
console.log(err)
})
- ** 使用 Promise 封装 ajax 中的 get 方法
// 使用 Promise 封装 ajax 的 get 方法
function pGet(url) {
return new Promise((resolve, reject) => {
// XMLHttpRequest 在 node 环境下不支持使用
let xhr = new XMLHttpRequest()
xhr.onload = function () {
resolve(xhr.responseText)
}
xhr.onerror = function (err) {
reject(err)
}
xhr.open('get', url, true)
xhr.send()
})
}
pGet('./c.txt').then((data) => {
console.log(data)
}, (err) => {
console.log(err)
})
7.1 Promise 数据库操作案例
let mongoose = require('mongoose')
mongoose.connect('mongodb://127.0.0.1:27017/test', {
useNewUrlParser: true,
useUnifiedTopology: true
})
mongoose.Promise = global.Promise
// 设计集合结构(表结构)
let userSchema = new mongoose.Schema({
username: {
type: String,
required: true // 必须有
},
password: {
type: String,
required: true
},
email: {
type: String
}
})
// 将文档结构发布为模型
let User = mongoose.model('User', userSchema)
User.findOne({
username: '张三'
}, (err, ret) => {
if (err) {
console.log('出错啦...')
} else {
console.log('可以执行下面的保存操作啦...', ret)
}
}).then((user) => {
if (user) {
console.log('用户已存在!')
} else {
// 用户不存在 可以注册
return new User({
username: '张三',
password: '147258369',
email: '无'
}).save((err) => {
if (err) {
console.log('保存失败!')
} else {
console.log('保存成功!')
}
})
}
}).then((ret) => {
})
*
8. path模块
-
path.basename
- 获取一个路径的文件名(默认包含扩展名)
-
**path.resolve(…arr) **
- 自动将数组解析成一个绝对的路径 其中数组需要解构
-
path.dirname
- 获取一个路径中的目录部分
-
path.extname
- 获取一个路径中的扩展名部分
-
path.parse
- 把一个路径转为一个对象
- 包含:root 根路径
- dir 目录
- base 包含后缀名的文件名
- ext 后缀名
- name 不包含后缀名的文件名
- 把一个路径转为一个对象
-
path.join
- 当你需要进行路径拼接的时候,推荐使用该方法
-
path.isAbsoulte
- 判断一个路径是否是绝对路径
-
Node 中的其他成员
-
在每个模块中,除了
require
、exports
等模块相关API 之外,还有两个特殊的成员_dirname
可以动态的用户获取当前文件所属目录的绝对路径_filename
可以动态的用来获取当前文件的绝对路径- 在文件操作中,使用相对路径是不可靠的,因为在 Node 中文件操作的路径被设计为相对于执行 node 命令所处的路径(不是错误 而是 node 是这样设计的
-
_dirname
和filename
是不受执行 node 命令所属路径影响的- 推荐多使用这两个动态的绝对路径
*
9. MD5加密和系统模块
9.1. MD5加密
*
导入包: npm install blueimp-md5
let md5 = require('blueimp-md5')
let password = md5(md5(body.password))
9.2. 系统模块
let os = require('os')
// 查看 CPU 信息
console.log(os.cpus())
// 查看整个内存大小
console.log(os.totalmem())
// 查看系统架构 x64
console.log(os.arch())
// 查看剩余内存量
console.log(os.freemem())
// 查看系统平台
console.log(os.platform())
*
10. Session 保存登录状态
-
在Express 这个框架中 默认不支持 Session 和Cookie
-
**使用第三方中间件:express-session 来解决
-
安装第三方中间件
npm install express-session
-
配置
// 该插件会为 req 对象添加一个成员 req.session 默认是一个对象 // 导入模块 let session = require('express-session') // 配置(一定要在 app.use(router) 之前) // 当把这个插件配置好之后 可以提供 req.session 来访问和配置 Session 成员 // 添加 Session 数据 req.session.foo = 'bar' // 访问 Session 数据 req.session.foo app.use(session({ // 配置加密字符串, 它会在原有加密的基础上加上这个字符串拼起来去加密 // 目的是为了增加安全性, 防止客户端恶意伪造 secret: 'bright', resave: false, saveUninitialized: true // 设置为 true 后, 无论你是否使用 Session 都会生成 一把钥匙 }))
- 提示:默认 Session 数据是内存存储的,服务器一旦重启就会丢失,真正的生产环境会把 Session 进行持久化存储
-
*
11. Express 中的中间件
- 在 Express 中对中间件有几种分类
- 不关心请求路径和请求方法的中间件
- 也就是说任何请求都会进入这个中间件
- app.use()
- 一共有三个参数 request response next 方法是将控制权交给下一个 中间件
- 关心请求路径的中间件 以 /xxx 开头的路径中间件
- 调 next() 也是需要匹配的,并不是紧挨着的
- 不关心请求路径和请求方法的中间件
*
12. node 的输入与输出
// 导入 readline 包
let readline = require('readline')
let fs = require('fs')
// 实例化接口对象
let rl = readline.createInterface({
input: process.stdin,
output: process.stdout
})
// request 方法
// 设置 rl 提问事件
/* rl.question('你的名字是?', (answer) => {
console.log('我的名字是:' + answer)
// 不加 close 则程序不会结束
rl.close()
}) */
function rlQuestion (title) {
return new Promise((resolve, reject) => {
rl.question(title, (answer) => {
resolve(answer)
})
})
}
async function createPackage () {
let name = await rlQuestion('你的包名?')
let description = await rlQuestion('你的描述信息?')
let main = await rlQuestion('主程序入口文件?')
let author = await rlQuestion('你的包的作者?')
let content = `{
"name": "${name}",
"version": "1.0.0",
"description": "${description}",
"main": "${main}",
"scripts": {
"test": "echo \\"Error: no test specified\\" && exit 1"
},
"keywords": [],
"author": "${author}",
"license": "ISC"
}`
console.log(content)
let fd = fs.openSync('package0.json', 'w')
fs.write(fd, content, () => {})
// 最后写完关闭, 关闭输入进程
rl.close()
}
createPackage()
// 监听 rl.close() 当调用时 结束输入输出流
rl.on('close', () => {
process.exit(0)
})
*
13. node 事件 (是单线程的)
-
原始的写法
let fs = require('fs') fs.readFile('./1.txt', {flag: 'r', encoding: 'utf-8'}, (err, data) => { if (err) { console.log(err) } else { brEvent.emit('fileSuccess', data) } }) let brEvent = { event: { // fileSuccess: [fn,fn] }, on:function (eventName, eventFn) { if(this.event[eventName]) { this.event[eventName].push(eventFn) } else { this.event[eventName] = [] this.event[eventName].push(eventFn) } }, emit:function (eventName, eventMsg) { if (this.event[eventName]) { this.event[eventName].forEach(itemFn => { itemFn(eventMsg) }) } } } brEvent.on('fileSuccess', (eventMsg) => { console.log('数据库查看所有学员信息', eventMsg) }) brEvent.on('deleteStu', (eventMsg) => { console.log('删库跑路', eventMsg) })
-
node提供的
let events = require('events') let ee = new events.EventEmitter() let fs = require('fs') /* ee.on('监听的事件的名称', '触发时传来的东西') ee.emit('触发某一事件的名称', '传递的参数') */ ee.on('hello', (eventMsg) => console.log(eventMsg)) ee.on('world', eventMsg => console.log(eventMsg)) // 封装 读取文件的 Promise 版本 function brReadFile (path) { return new Promise((resolve, reject) => { fs.readFile(path, {encoding: 'utf-8'}, (err, data) => { if (err) { console.log(err) } else { // console.log(data) resolve(data) } }) }) } brReadFile('./1.txt').then((data) => { ee.emit('hello', 'hello执行了' + data) ee.emit('world', 'world执行了' + data) }) async function test () { let data = await brReadFile('./1.txt') ee.emit('hello', 'hello又一次执行了' + data) } test()