Node 操作 MySQL数据库
安装:
npm install --save mysql
异步编程
回调函数
Promise
无法保证顺序的代码:
var fs = require('fs')
fs.readFile('a.text', 'utf8', function(err, data) {
if (err) {
throw err
}
console.log(data)
fs.readFile('b.text', 'utf8', function(err, data) {
if (err) {
throw err
}
console.log(data)
fs.readFile('c.text', 'utf8', function(err, data) {
if (err) {
throw err
}
console.log(data)
})
})
})
注意:
之前的读取文件 return 结束函数的方式,在开发中常常使用 throw err 的形式抛出异常
多个异步编程的情况,无法保证回调函数的执行顺序(多线程调度机制),只能通过异步嵌套异步的形式保证顺序。代码太繁琐,不好修改。
为了解决以上编码方式带来的问题(回调地狱嵌套),所以在ECMAscript 6 中新增了一个 API:Promise
- Promise : 保证承诺
Promise 容器:
- 容器中存放了一个异步任务
- 任务默认有三种状态
- 默认状态:pending 正在进行(之前网站响应有过这个状态)
- pending 状态发生变化,变为两种状态其中的一种
- Resolved 解决 成功
- Rejected 失败
- 状态改变之后不能再改变成另一种状态
在ECMAscript 6 中新增了一个 API Promise
Promise 是一个构造函数
使用:
创建一个 Promise 容器
-
给别人一个承诺
Promise 容器一旦创建,就开始执行里面的代码new Promise(function () { //一个异步任务 })
注意:承诺本身不是异步的,只是它存放的异步任务是异步的。Promise 本身不是异步的,但是内部往往都是封装一个异步任务
Promise 的具体使用:
[图片上传失败…(image-d65b7a-1536318692721)]
var p1 = new Promise(function (resolve, reject) {
fs.readFile('a.txt', function (err, data) { //异步任务
if (err) {
//容器中的任务失败
//把容器中的 Pending 状态变为 Rejected
reject(err)
} else {
//承诺容器中的任务成功了
//把容器中的 Pending 状态改为成功 Resolved
//也就是说这里调用的resolve 方法实际上就是then 方法传递的那个 function
resolve(data)
}
})
})
//p1 就是那个承诺
//当p1 成功了 然后(then) 做指定的操作
//then 方法接收的第一个 function 就是容器中的 resolve 函数中的数据
//调用了reject 就相当于调用了 then 方法的第二个参数函数
p1
.then(function (data) {
console.log(data)
//return 123
// 当前成功函数 return 的结果就可以在后面的 then 中function 接收到
//当你 return 123 后面就会接收到 123
//return hello 后面就会接收到 'hello'
// 没有 return 后面收到的就是哦undefined
// 上面这些事原理
// 真正使用的是:我们可以 return 一个 Promise 对象
//当 return 一个 Promise 对象的时候,后续的 then 中的方法的第一个参数会作为 p2 的 resolve函数的结果
return p2
}, function (err) {
console.log('读取文件失败', err)
})
以上情况称为异步调用链式编程。
- Promise 应用场景
在开发的过程中,通过多个接口获取的数据或者多个ajax请求获取的数据,可以使用Promise 来写
jquery 中的ajax 方法已经支持 Promise ,可以使用 then(Promise对象使用then 方法) 方法。
在需要不同的请求获取结果的时候,需要使用Promise解决方案,可以链式编程获取异步处理结果。 - callback 注意事项(开发中的小事):
[图片上传失败…(image-97a1fd-1536318692721)]
图中的fn() 函数调用没有传递 callback 参数(会出错),因此需要使用图中到的解决方案
注意:
1. 要使用 .then() 方法,必须要支持 Promise
2. mongoose 的查询操作都是异步操作,都可以使用 .then 方法
3. .then() 方法的执行,必须要等到 Promise 的状态改变
中间件概念
-
middlewares
-
例如开发一个模块解决一个功能
一般采取如下的形式module.exports = function (req, res) { req.body = {} } //在调用的模块中使用下列函数 query(req) //把req 对象传递到执行函数中
调用返回的函数,传递req 对象就可以让该对象拥有body 属性。例如在express中使用 bodyParse 的配置和 template 的配置,都需要先配置之后才会给 req 对象添加一个方法
Express 中间件(app.use的用法)
中间件: 处理请求的,本质就是函数。
中间件主要执行规则就是前面的中间件会对后面的中间件进行封堵。next() 方法也要求匹配,如果路径不匹配也不行。next 是执行后面的,不是执行后一个
在 Express 中,对中间件有几种分类。
同一个请求所经历的中间件都是同一个请求对象和响应对象。传递相同的req 对象和 res 对象。-
应用程序级别中间件
-
不关心请求路径的请求方法的中间件
也就是说任何请求(不关心请求路径和请求方法)都会进入这个中间件
使用 app.use() 方法来调用,参数一般为函数app.use(function (req, res, next) { })
- 中间件本身就是一个方法,该方法接收三个参数
-
Request 请求对象
-
Response 响应对象
-
next 下一个中间件,next 本身为函数,默认中间件不会执行下一个中间件,调用 next() 方法之后,会执行下一个中间件。
app.use(function (req, res, next) { console.log(1) next() }) app.use(function (req, res, next) { console.log(2) })
-
当一个请求进入一个中间件之后,如果不调用 next 则会停留在当前中间件。所以next 是一个方法,用来调用下一个中间件的。
- 中间件本身就是一个方法,该方法接收三个参数
-
-
关心请求路径的中间件(以 /xxx 开头的路径中间件)。
app.use('/a', function (req, res, next) { console.log(req.url) //此处打印的 url 是出去 /a 后面的url })
当请求路径是以 a开头的情况,执行function 里面的代码
当请求进来,会从第一个中间件开始进行匹配。(代码顺序)
如果匹配,则进来。
如果请求进入中间件之后,没有调用next() 方法,则代码会停留在这个中间件中。
如果调用了next 则向后查找匹配的中间件
如果不匹配,则继续判断匹配下一个中间件。
- 如果没有能匹配的中间件,express 会默认输出:Cannot GET 路径(POST 请求则换成POST)
-
路由级别的中间件
-
除了以上中间件之外,还有一种最常用的
严格匹配请求方法和请求路径的中间件
app.get 和 app.postapp.get('/a', function (req, res, next) { console.log('aaa') next() }) app.get('/a', function (req, res, next) { console.log('bbb') })
上述例子中下面的不会覆盖上面的中间件
总结
- express 框架下编程也可以使用原生的node编写
- 原生的node 使用 res.end() 方法来结束请求,express 框架使用 res.send() 方法来结束请求
- 原生的node使用自己判断的方式来开发静态资源;express 框架使用 app.use() (中间件形式)方法来开放静态资源