我们在使用express框架的时候,经常遇到中间件。
中间件给人的感觉是非常好用的,那么它的原理是怎样的呢?今天我们试着写一下看看。
我们要实现的大概是这样一个东西:
function myexpress() {
}
var app = myexpress();
function middlewareA(req, res, next) {
console.log('middlewareA before next()');
next();
console.log('middlewareA after next()');
}
function middlewareB(req, res, next) {
console.log('middlewareB before next()');
next();
console.log('middlewareB after next()');
}
function middlewareC(req, res, next) {
console.log('middlewareC before next()');
next();
console.log('middlewareC after next()');
}
//注册回调函数
app.use(middlewareA);
app.use(middlewareB);
app.use(middlewareC);
//调用
app()
思路大家应该可以想到,还是利用观察者模式:
use订阅回调函数,在next触发。
不过有两个问题大家可以先思考一下:
1、myexpress返回什么?
2、怎么执行订阅的回调函数?
先看第一个问题。这里令人困惑的地方是:
myexpress得具有use方法,同时还得是个闭包函数才行。
var app = myexpress()
app.use(...)//app得具有use方法
app()//闭包
如果myexpress返回的是一个对象:
function express() {
var subs = []
return {
use:function(cb){
subs.push(cb)
}
}
}
var app = express()
app.use(function(){
console.log('test')
})
app()//出错了~~
如果是闭包,那use方法就没地方放了:
function express() {
var subs = []
return function(){
}
}
var app = express()
app.use(function(){//出错了~~
console.log('test')
})
app()
咋办呢?
其实很简单,闭包我们通常习惯使用匿名函数,自然无法再多追加use方法,而使用具名函数即可解决这个问题。
function express() {
var subs = []
var func = function(){//具名函数
}
func.use = function(cb){//具名函数下追加use方法
subs.push(cb)
}
return func //返回具名函数
}
var app = express()
app.use(function(){
console.log('test')
})
app()
下面看第二个问题。
观察者的订阅场景比较清晰,就是在调用use的时候注册回调函数;但触发场景有点令人困惑,因为它是在回调函数内部调用next的,如何捕获并执行到next呢?
这其实还是高阶函数的问题,在手写promise时也遇到过:
function express() {
var subs = []
var func = function(){//具名函数
function next(){
var cb = null
if(subs.length>0){
cb = subs.shift()//出列一个回调函数
cb(next)//高阶函数最终执行的是他!
} else {
return;//如果队列为空,返回
}
}
next()//app()时开始执行
}
func.use = function(cb){//具名函数下追加use方法
subs.push(cb)
}
return func //返回具名函数
}
var app = express()
app.use(function(next){
console.log('test')
next()
})
app()
这样最终代码也就写出来了:
function express() {
var subs = []
var func = function(){//具名函数
function next(){
var cb = null
if(subs.length>0){
cb = subs.shift()//出列一个回调函数
cb(next)//高阶函数最终执行的是他!
} else {
return;
}
}
next()//app()时开始执行
}
func.use = function(cb){//具名函数下追加use方法
subs.push(cb)
}
return func //返回具名函数
}
var app = express()
function middlewareA(next) {
console.log('middlewareA before next()');
next();
console.log('middlewareA after next()');
}
function middlewareB(next) {
console.log('middlewareB before next()');
next();
console.log('middlewareB after next()');
}
function middlewareC(next) {
console.log('middlewareC before next()');
next();
console.log('middlewareC after next()');
}
app.use(middlewareA);
app.use(middlewareB);
app.use(middlewareC);
app()
网友评论