nodejsexpressuse传值_再也不怕⾯试官问你express和koa的
区别了
前⾔
⽤了那么多年的express.js,终于有时间来深⼊学习express,然后顺便再和koa2的实现⽅式对⽐⼀下。
⽼实说,还没看express.js源码之前,⼀直觉得express.js还是很不错的,⽆论从api设计,还是使⽤上都是可以的。但是这次阅读完express代码之后,我可能改变想法了。
虽然express.js有着精妙的中间件设计,但是以当前js标准来说,这种精妙的设计在现在可以说是太复杂。
⾥⾯的层层回调和递归,不花⼀定的时间还真的很难读懂。⽽koa2的代码呢?简直可以⽤四个字评论:精简彪悍!仅仅⼏个⽂件,⽤上最新的js标准,就很好实现了中间件,代码读起来⼀⽬了然。
⽼规矩,读懂这篇⽂章,我们依然有⼀个简单的demo来演⽰: express-vs-koa
1、express⽤法和koa⽤法简单展⽰
如果你使⽤express.js启动⼀个简单的服务器,那么基本写法应该是这样:
const express = require('express')
const app = express()
const router = express.Router()
app.use(async (req, res, next) => {
console.log('I am the first middleware')
next()
console.log('first middleware end calling')
})
app.use((req, res, next) => {
console.log('I am the second middleware')
next()
console.log('second middleware end calling')
})
<('/api/test1', async(req, res, next) => {
console.log('I am the router middleware => /api/test1')
res.status(200).send('hello')
})
<('/api/testerror', (req, res, next) => {
console.log('I am the router middleware => /api/testerror')  throw new Error('I am error.')
})
app.use('/', router)
app.use(async(err, req, res, next) => {
原生js和js的区别if (err) {
console.log('last middleware catch error', err)
res.status(500).send('server Error')
return
}
console.log('I am the last middleware')
next()
console.log('last middleware end calling')
})
app.listen(3000)
console.log('server listening at port 3000')
换算成等价的koa2,那么⽤法是这样的:
const koa = require('koa')
const Router = require('koa-router')
const app = new koa()
const router = Router()
app.use(async(ctx, next) => {
console.log('I am the first middleware')
await next()
console.log('first middleware end calling')
})
app.use(async (ctx, next) => {
console.log('I am the second middleware')
await next()
console.log('second middleware end calling')
})
<('/api/test1', async(ctx, next) => {
console.log('I am the router middleware => /api/test1')
ctx.body = 'hello'
})
<('/api/testerror', async(ctx, next) => {
throw new Error('I am error.')
})
app.utes())
app.listen(3000)
console.log('server listening at port 3000')
如果你还感兴趣原⽣nodejs启动服务器是怎么使⽤的,可以参考demo中的这个⽂件:node.js
于是⼆者的使⽤区别通过表格展⽰如下(知乎不⽀持markdown也是醉了~表格只能截图了~):
上表展⽰了⼆者的使⽤区别,从初始化就看出koa语法都是⽤的新标准。在挂载路由中间件上也有⼀定的差异性,这是因为⼆者内部实现机制的不同。其他都是⼤同⼩异的了。
那么接下去,我们的重点便是放在⼆者的中间件的实现上。
2、express.js中间件实现原理
我们先来看⼀个demo,展⽰了express.js的中间件在处理某些问题上的弱势。demo代码如下:
const express = require('express')
const app = express()
const sleep = (mseconds) => new Promise((resolve) => setTimeout(() => {
console.log('')
resolve()
}, mseconds))
app.use(async (req, res, next) => {
console.log('I am the first middleware')
const startTime = w()
console.log(`================ start ${hod} ${req.url}`, { query: req.query, body: req.body });  next()
const cost = w() - startTime
console.log(`================ end ${hod} ${req.url} ${res.statusCode} - ${cost} ms`)
})
app.use((req, res, next) => {
console.log('I am the second middleware')
next()
console.log('second middleware end calling')
})
<('/api/test1', async(req, res, next) => {
console.log('I am the router middleware => /api/test1')
await sleep(2000)
res.status(200).send('hello')
})
app.use(async(err, req, res, next) => {
if (err) {
console.log('last middleware catch error', err)
res.status(500).send('server Error')
return
}
console.log('I am the last middleware')
await sleep(2000)
next()
console.log('last middleware end calling')
})
app.listen(3000)
console.log('server listening at port 3000')
该demo中当请求/api/test1的时候打印结果是什么呢?
I am the first middleware
================ start GET /api/test1
I am the second middleware
I am the router middleware => /api/test1
second middleware end calling
================ end GET /api/test1 200 - 3 ms
如果你清楚这个打印结果的原因,想必对express.js的中间件实现有⼀定的了解。
我们先看看第⼀节demo的打印结果是:
I am the first middleware
I am the second middleware
I am the router middleware => /api/test1
second middleware end calling
first middleware end calling
这个打印符合⼤家的期望,但是为什么刚才的demo打印的结果就不符合期望了呢?⼆者唯⼀的区别就是第⼆个demo加了异步处理。有了异步处理,整个过程就乱掉了。因为我们期望的执⾏流程是这样的:
I am the first middleware
================ start GET /api/test1
I am the second middleware
I am the router middleware => /api/test1
second middleware end calling
================ end GET /api/test1 200 - 3 ms
那么是什么导致这样的结果呢?我们在接下去的分析中可以得到答案。
2.1、express挂载中间件的⽅式
要理解其实现,我们得先知道express.js到底有多少种⽅式可以挂载中间件进去?熟悉express.js的童鞋知道吗?知道的童鞋可以⼼⾥默默列举⼀下。
⽬前可以挂载中间件进去的有:(HTTP Method指代那些http请求⽅法,诸如Get/Post/Put等等)
app.use
app.[HTTP Method]
app.all
app.param
router.all
router.use
router.param
router.[HTTP Method]
2.2、express中间件初始化
express代码中依赖于⼏个变量(实例):app、router、layer、route,这⼏个实例之间的关系决定了中间件初始化后形成⼀个数据模型,画了下⾯⼀张图⽚来展⽰:
图中存在两块Layer实例,挂载的地⽅也不⼀样,以express.js为例⼦,我们通过调试到更加形象的例⼦:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。