91 # 实现 express 的优化处理
上一节实现 express 的请求处理,这一节来进行实现 express 的优化处理
- 让 layer 提供 match 方法去匹配 pathname,方便拓展
- 让 layer 提供 handle_request 方法,方便拓展
- 利用第三方库
methods批量生成方法 - 性能优化问题
- 进行路由懒加载,当进行
get/post...请求时,或者 listen 时,才加载 route - layer 进行加速匹配,在 layer 层判断是否请求方法在 route 里有
- 进行路由懒加载,当进行
methods 库地址: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) {// 产生 routelet 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;
相关文章:
91 # 实现 express 的优化处理
上一节实现 express 的请求处理,这一节来进行实现 express 的优化处理 让 layer 提供 match 方法去匹配 pathname,方便拓展让 layer 提供 handle_request 方法,方便拓展利用第三方库 methods 批量生成方法性能优化问题 进行路由懒加载&#…...
arcgis拓扑检查实现多个矢量数据之间消除重叠区域
目录 环境介绍: 操作任务: 步骤: 1、数据库和文件结构准备 2、建立拓扑规则 3、一直下一页默认参数后,进行拓扑检查 4、打开TP_CK_Topology,会自动带出拓扑要素,红色区域为拓扑错误的地方࿱…...
基于Vue+ELement搭建登陆注册页面实现后端交互
🎉🎉欢迎来到我的CSDN主页!🎉🎉 🏅我是Java方文山,一个在CSDN分享笔记的博主。📚📚 🌟推荐给大家我的专栏《ELement》。🎯🎯 …...
JS获取经纬度, 并根据经纬度得到城市信息
在JavaScript中,获取经纬度通常需要使用定位服务,比如HTML5的Geolocation API。然而拿到坐标后,将经纬度转换为城市信息,则需要使用逆地理编码服务接口,比如百度或者高德的 API, 但是他们收费都很高, 我们可以使用一些…...
mac m1 docker安装nacos
文章目录 引言I m1安装docker1.1 Docker 下载1.2 终端Docker相关命令II docker安装nacos2.1 安装nacos2.2 镜像启动see alsoMac 查看进程端口引言 使用docker方式安装是最方便的 I m1安装docker 1.1 Docker 下载 https://docs.docker.com/docker-for-mac/apple-silicon/点击…...
位段 联合体 枚举
Hello好久不见,今天分享的是接上次结构体没有分享完的内容,这次我们讲讲位段 枚举和联合体的概念以及他们的用法。 2.1 什么是位段 位段的声明和结构是类似的,有两个不同: 1.位段的成员必须是 int、unsigned int 或signed int 。 …...
PHP循环获取Excel表头字母A-Z,当超过时输出AA,AB,AC,AD······
PHP循环获取Excel表头字母A-Z,当超过时输出AA,AB,AC,AD PHP循环生成Excel的列字母表 $count_num 26 * 27; $letter A; $arr []; while($count_num--){$arr[] $letter;$letter; }结果如下: 转为JSON更为直观: ["A","B&…...
识别准确率达 95%,华能东方电厂财务机器人实践探索
摘 要:基于华能集团公司大数据与人工智能构想理念,结合东方电厂实际工作需要,财务工作要向数字化、智能化纵深推进,随着财务数字化转型和升级加速,信息化水平不断提升,以及内部信息互联互通不断加深&#x…...
代码随想录算法训练营 单调栈part03
一、柱状图中最大的矩形 84. 柱状图中最大的矩形 - 力扣(LeetCode) 单调栈很重要的性质,就是单调栈里的顺序,是从小到大还是从大到小。 栈顶和栈顶的下一个元素以及要入栈的三个元素组成了我们要求最大面积的高度和宽度&#x…...
使用 MyBatisPlus 的注解方式进行 SQL 查询,它结合了条件构造器(Wrapper)和自定义 SQL 片段来构建查询语句。
MyBatis-Plus 是一个基于 MyBatis 的增强工具,它提供了一套方便的注解方式来进行 SQL 查询。其中,它结合了条件构造器(Wrapper)和自定义 SQL 片段来构建查询语句。 官网:条件构造器 | MyBatis-Plus 1、使用 Wrapper …...
Python中统计单词出现的次数,包含(PySpark方法)
思路: 定义一个函数,使用open函数,将文本内容打开。 定义一个空字典和空列表,进行循环及条件判断操作def count_word(file_path):dict_data {} #定义一个空字典f open(file_path,"r",encoding"UTF-8")lis…...
探讨基于IEC61499 的分布式 ISA Batch 控制系统
ISA SP88 是批次过程控制的标准,对应的IEC标准是IEC 61512。该标准中一个重要的部分是配方管理(Recipe Management)。 所谓配方,是根据批量产品的要求,材料设定加工工艺,加工流程和参数。类似于传统制造业的…...
图论16(Leetcode863.二叉树中所有距离为K的结点)
答案: /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val x; }* }*/ class Solution {public List<Integer> distanceK(TreeNode root, TreeNode tar…...
【小沐学C++】C++ MFC中嵌入64位ActiveX控件(VS2017)
文章目录 1、简介1.1 MFC1.2 ActiveX 2、VS2017添加ActiveX控件结语 1、简介 1.1 MFC Microsoft 基础类 (MFC) 库针对大部分 Win32 和 COM API 提供面向对象的包装器。 虽然此包装器可用于创建极为简单的桌面应用程序,但当你需要开发具有多个控件的更复杂的用户界…...
Linux常用命令—find命令大全
文章目录 一、find命令常用功能1、find命令的基本信息如下。2、按照文件名搜索3、按照文件大小搜索4、按照修改时间搜索5、按照权限搜索举例:6、按照所有者和所属组搜索7、按照文件类型搜索8、逻辑运算符 一、find命令常用功能 1、find命令的基本信息如下。 命令名…...
form组件的封装(element ui ) 简单版本
当你使用Vue.js构建Web应用时,封装可复用组件是提高开发效率和代码可维护性的关键之一。在这篇文章中,我们将探讨如何使用Vue.js来创建一个通用的表单组件,以及如何将它封装成一个可配置的组件。 实现思路 拿下表单模板一个个的改造&#x…...
树形DP杂题
引 对老师布置的题目稍微记录一下吧 也算对树形 D P DP DP 的巩固 T1 Ostap and Tree 题目传送门 由于有 距离 k 距离k 距离k 的限制,设计二维 d p dp dp 设计状态: f i , j : i 的子树内,离 i 最近的染色点与 i 距离为 j 且若 j <…...
Webpack使用plugin插件自动在打包目录生成html文件
我们使用html-webpack-plugin插件可以自动在打包代码目录生成html文件 使用步骤: 一、安装依赖 在控制台中输入如下代码: npm i -D html-webpack-plugin 二、在webpack.config.js中配置插件 const HTMLPlugin require("html-webpack-plugin&q…...
图像处理与计算机视觉--第一章-计算机视觉简介-10问
第一章-计算机视觉简介-10问 1.CV与AI的关系是什么? CV(Computer Vision)是Al的子领域,它致力于使计算机能够理解和解释图像和数据,CV借助AI技术,比如深度学习/机器学习,实现目标识别,分析和处理任务。AI提供了CV所需要的算法…...
LeetCode 80. 删除有序数组中的重复项 II
文章目录 一、题目二、Java 题解 一、题目 给你一个有序数组 nums,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。 不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...
JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
ios苹果系统,js 滑动屏幕、锚定无效
现象:window.addEventListener监听touch无效,划不动屏幕,但是代码逻辑都有执行到。 scrollIntoView也无效。 原因:这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作,从而会影响…...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...
Qt 事件处理中 return 的深入解析
Qt 事件处理中 return 的深入解析 在 Qt 事件处理中,return 语句的使用是另一个关键概念,它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别:不同层级的事件处理 方…...
Modbus RTU与Modbus TCP详解指南
目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...
从物理机到云原生:全面解析计算虚拟化技术的演进与应用
前言:我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM(Java Virtual Machine)让"一次编写,到处运行"成为可能。这个软件层面的虚拟化让我着迷,但直到后来接触VMware和Doc…...
Vue 3 + WebSocket 实战:公司通知实时推送功能详解
📢 Vue 3 WebSocket 实战:公司通知实时推送功能详解 📌 收藏 点赞 关注,项目中要用到推送功能时就不怕找不到了! 实时通知是企业系统中常见的功能,比如:管理员发布通知后,所有用户…...
