上一节实现 express 的请求处理,这一节来进行实现 express 的优化处理
methods
批量生成方法get/post...
请求时,或者 listen 时,才加载 routemethods 库地址:https://www.npmjs.com/package/methods
[
'acl', 'bind', 'checkout',
'connect', 'copy', 'delete',
'get', 'head', 'link',
'lock', 'm-search', 'merge',
'mkactivity', 'mkcalendar', 'mkcol',
'move', 'notify', 'options',
'patch', 'post', 'pri',
'propfind', 'proppatch', 'purge',
'put', 'rebind', 'report',
'search', 'source', 'subscribe',
'trace', 'unbind', 'unlink',
'unlock', 'unsubscribe'
]
批量生成方法测试 demo 如下
const express = require("./kaimo-express");
const app = express();
app.get("/", (req, res, next) => {
res.end("get okk end");
});
app.post("/", (req, res, next) => {
res.end("post okk end");
});
app.listen(3000, () => {
console.log(`server start 3000`);
console.log(`在线访问地址:http://localhost:3000/`);
});
控制台执行下面命令:
curl -v -X POST http://localhost:3000/
layer 进行加速匹配 demo
const express = require("./kaimo-express");
const app = express();
app.post("/", (req, res, next) => {
res.end("post okk end");
});
app.put("/", (req, res, next) => {
res.end("put okk end");
});
app.delete("/", (req, res, next) => {
res.end("delete okk end");
});
app.options("/", (req, res, next) => {
res.end("delete okk end");
});
app.listen(3000, () => {
console.log(`server start 3000`);
console.log(`在线访问地址:http://localhost:3000/`);
});
然后去访问:http://localhost:3000/
,可以看到没有优化的时候会请求这些方法
优化的代码如下:
application.js
const http = require("http");
const Router = require("./router");
const methods = require("methods");
console.log("methods----->", methods);
function Application() {}
// 调用此方法才开始创建,不是创建应用时直接装载路由
Application.prototype.lazy_route = function () {
if (!this._router) {
this._router = new Router();
}
};
methods.forEach((method) => {
Application.prototype[method] = function (path, ...handlers) {
this.lazy_route();
this._router[method](path, handlers);
};
});
Application.prototype.listen = function () {
const server = http.createServer((req, res) => {
function done() {
res.end(`kaimo-express Cannot ${req.method} ${req.url}`);
}
this.lazy_route();
this._router.handle(req, res, done);
});
server.listen(...arguments);
};
module.exports = Application;
router/index.js
const url = require("url");
const Route = require("./route");
const Layer = require("./layer");
const methods = require("methods");
function Router() {
// 维护所有的路由
this.stack = [];
}
Router.prototype.route = function (path) {
// 产生 route
let route = new Route();
// 产生 layer 让 layer 跟 route 进行关联
let layer = new Layer(path, route.dispatch.bind(route));
// 每个路由都具备一个 route 属性,稍后路径匹配到后会调用 route 中的每一层
layer.route = route;
// 把 layer 放到路由的栈中
this.stack.push(layer);
return route;
};
methods.forEach((method) => {
Router.prototype[method] = function (path, handlers) {
// 1.用户调用 method 时,需要保存成一个 layer 当道栈中
// 2.产生一个 Route 实例和当前的 layer 创造关系
// 3.要将 route 的 dispatch 方法存到 layer 上
let route = this.route(path);
// 让 route 记录用户传入的 handler 并且标记这个 handler 是什么方法
route[method](handlers);
};
});
Router.prototype.handle = function (req, res, out) {
console.log("请求到了");
// 需要取出路由系统中 Router 存放的 layer 依次执行
const { pathname } = url.parse(req.url);
let idx = 0;
let next = () => {
// 遍历完后没有找到就直接走出路由系统
if (idx >= this.stack.length) return out();
let layer = this.stack[idx++];
// 需要判断 layer 上的 path 和当前请求路由是否一致,一致就执行 dispatch 方法
if (layer.match(pathname)) {
// 将遍历路由系统中下一层的方法传入
// 加速匹配,如果用户注册过这个类型的方法在去执行
if (layer.route.methods[req.method.toLowerCase()]) {
layer.handle_request(req, res, next);
} else {
next();
}
} else {
next();
}
};
next();
};
module.exports = Router;
route.js
const Layer = require("./layer");
const methods = require("methods");
function Route() {
this.stack = [];
// 用来描述内部存过哪些方法
this.methods = {};
}
Route.prototype.dispatch = function (req, res, out) {
// 稍后调用此方法时,回去栈中拿出对应的 handler 依次执行
let idx = 0;
console.log("this.stack----->", this.stack);
let next = () => {
// 遍历完后没有找到就直接走出路由系统
if (idx >= this.stack.length) return out();
let layer = this.stack[idx++];
console.log("dispatch----->", layer.method);
if (layer.method === req.method.toLowerCase()) {
layer.handle_request(req, res, next);
} else {
next();
}
};
next();
};
methods.forEach((method) => {
Route.prototype[method] = function (handlers) {
console.log("handlers----->", handlers);
handlers.forEach((handler) => {
// 这里的路径没有意义
let layer = new Layer("/", handler);
layer.method = method;
// 做个映射表
this.methods[method] = true;
this.stack.push(layer);
});
};
});
module.exports = Route;
layer.js
function Layer(path, handler) {
this.path = path;
this.handler = handler;
}
Layer.prototype.match = function (pathname) {
return this.path === pathname;
};
Layer.prototype.handle_request = function (req, res, next) {
this.handler(req, res, next);
};
module.exports = Layer;