上一篇理解Express的使用之後, 再總結一篇Express中間件的簡單實現原理。 我們知道Express中間件就是一個個的函數, 那麼怎麼讓這些函數有序的執行呢? 那就需要我們調用 函數。其實 函數調用的就是下一個中間件函數。 以下代碼實現了簡單的 註冊中間件, 以及 、`post`方式的中間件 ...
上一篇理解Express的使用之後, 再總結一篇Express中間件的簡單實現原理。
我們知道Express中間件就是一個個的函數, 那麼怎麼讓這些函數有序的執行呢? 那就需要我們調用 next
函數。其實 next
函數調用的就是下一個中間件函數。
以下代碼實現了簡單的 app.use
註冊中間件, 以及 get
、post
方式的中間件。其他請求方式的中間件實現同理
核心代碼:
const next = () => {
const stack = stacks.shift()
if(stack) {
stack(req, res, next)
}
}
next()
stacks就是一個數組隊列, 存放所有符合規則的中間件函數。遵循先進先出
的原則。也就是最先註冊的中間件函數最先執行。
實現代碼
const http = require('http')
const slice = Array.prototype.slice
class Express {
constructor() {
this.router = {
all: [], // 匹配所有額中間件函數
get: [],
post: []
}
}
/**
* 這裡整合中間件
* @param {string} path
* @returns {object}
*/
middlewareHandler(path) {
const info = {}
if (typeof path === 'string') {
info.path = path
info.stack = slice.call(arguments, 1) // 中間件數組
} else {
info.path = '/'
info.stack = slice.call(arguments, 0)
}
return info
}
use() {
const allStack = this.middlewareHandler(...arguments)
this.router.all.push(allStack)
}
get() {
const getStack = this.middlewareHandler(...arguments)
this.router.get.push(getStack)
}
post() {
const postStack = this.middlewareHandler(...arguments)
this.router.post.push(postStack)
}
/**
*
* @param {string} method
* @param {string} url
* @returns {Array}
*/
accordStack(method, url) {
let stacks = []
stacks = stacks.concat(this.router.all)
stacks = stacks.concat(this.router[method])
return stacks
.filter(stack => {
return url.indexOf(stack.path) !== -1
}).map(item => item.stack[0])
}
handler(req, res, stacks) {
// 函數表達式
const next = () => {
const stack = stacks.shift()
if(stack) {
stack(req, res, next)
}
}
next()
}
callback() {
return (req, res) => {
res.json = data => {
res.setHeader('Content-Type', 'application/json')
res.end(JSON.stringify(data))
}
// 拿到請求的方法和url, 對中間件函數進行篩選
const {method, url} = req
const stacks = this.accordStack(method.toLowerCase(), url)
this.handler(req, res, stacks)
}
}
listen(...args) {
const server = http.createServer(this.callback())
server.listen(...args)
}
}
// 工廠模式, 導出一個實例對象
module.exports = () => {
return new Express()
}