面试经常会问到一些原理性的东西,比如express,知道你会用,但可能就会问你实现的原理是什么,废话不多说。
express的所有服务端逻辑处理都是通过中间件来实现的,中间件是一个函数,而app.use()方法就是去装载这些函数,并放入一个数组中。
当前端一个请求传到服务器的时候,首先会经过request,然后是一系列的服务端处理,也就是中间件处理,存放于数组中的中间件采用后进先出的栈模式处理请求,最先入栈的中间件处理完请求之后,通过next将执行权交给第二个入栈的中间件,依次类推,直到数组末尾或者中间某个中间件没有调用next()函数,最后再将处理完的结果response回前端。
接下来让我们自己来简单实现一下:
/**
* 仿照express实现中间件的功能
*
* Created by haoxin on 2018/7/9.
*/
var http = require('http');
/**
* 仿express实现中间件机制
*
* @return {app}
*/
var express = () => {
var funcs = []; // 待执行的函数数组
var app = (req, res) => {
var i = 0;
var next = () => {
var task = funcs[i++]; // 取出函数数组里的下一个函数
if (!task) { // 如果函数不存在,return
return;
}
task(req, res, next); // 否则,执行下一个函数
}
next();
}
/**
* use方法就是把函数添加到函数数组中
* @param task
*/
app.use = (task) => {
funcs.push(task);
}
return app; // 返回实例
}
// 下面是测试case
var app = express();
http.createServer(app).listen('3000', () => {
console.log('listening 3000....');
});
const middlewareA = (req, res, next) => {
if(req.url!=="/favicon.ico") { //防止重复请求
console.log('middlewareA before next()');
next();
console.log('middlewareA after next()');
}
res.end();
}
const middlewareB = (req, res, next) => {
console.log('middlewareB before next()');
next();
console.log('middlewareB after next()');
}
const middlewareC = (req, res, next) => {
console.log('middlewareC before next()');
next();
console.log('middlewareC after next()');
}
app.use(middlewareA);
app.use(middlewareB);
app.use(middlewareC);
打开命令行,切换到该文件目录下,执行
看到输出结果:
好了,接下来看看源码中的实现方式,直接上图:
首先是文件:node_modules/express/lib/application.js
然后是:node_modules/express/lib/router/route.js
然后是:node_modules/express/lib/router/index.js
参考:https://www.jianshu.com/p/797a4e38fe77