From 5a8763c7ba080cc9eb89a8d51be748865c3fe06d Mon Sep 17 00:00:00 2001 From: Rolando Santamaria Maso <4096860+jkyberneees@users.noreply.github.com> Date: Sat, 6 Apr 2024 10:26:42 +0200 Subject: [PATCH] Dependencies update + performance improvements (#37) * updating dependencies * improving performance * adding benchmarking tool --- bench.js | 111 +++++++++++++++++++++++++++++++++++++++ lib/next.js | 7 +-- lib/router/sequential.js | 4 +- lib/utils/queryparams.js | 20 ++++--- package.json | 8 +-- 5 files changed, 134 insertions(+), 16 deletions(-) create mode 100644 bench.js diff --git a/bench.js b/bench.js new file mode 100644 index 0000000..0d8b277 --- /dev/null +++ b/bench.js @@ -0,0 +1,111 @@ +const httpNext = require('./index') +const httpPrevious = require('0http') + +function getReqObject (url) { + const req = {} + req.method = 'GET' + req.url = url + + return req +} + +function getResObject () { + const res = {} + res.statusCode = null + res.setHeader = () => {} + res.writeHead = () => {} + res.end = () => {} + return res +} + +function setupRouter (router) { + router.use((req, res, next) => { + return next() + }) + + router.get('/', (req, res) => { + return res.end('OK') + }) + router.get('/:id', (req, res) => { + return res.end(req.params.id) + }) + router.get('/:id/error', () => { + throw new Error('Error') + }) +} + +const { router } = httpNext({ + cacheSize: 0, + id: '/' +}) +setupRouter(router) + +const { router: routerPrevious } = httpPrevious({ + cacheSize: 0 +}) +setupRouter(routerPrevious) + +import('mitata/src/cli.mjs').then(({ run, bench, group, baseline }) => { + group('Next Router', () => { + baseline('Base URL', () => { + const req = getReqObject('/') + const res = getResObject() + + router.lookup(req, res) + }) + bench('Parameter URL', () => { + const req = getReqObject('/0') + const res = getResObject() + + router.lookup(req, res) + }) + bench('Not Found URL', () => { + const req = getReqObject('/0/404') + const res = getResObject() + + router.lookup(req, res) + }) + bench('Error URL', () => { + const req = getReqObject('/0/error') + const res = getResObject() + + router.lookup(req, res) + }) + }) + + group('Previous Router', () => { + baseline('Base URL', () => { + const req = getReqObject('/') + const res = getResObject() + + routerPrevious.lookup(req, res) + }) + bench('Parameter URL', () => { + const req = getReqObject('/0') + const res = getResObject() + + routerPrevious.lookup(req, res) + }) + bench('Not Found URL', () => { + const req = getReqObject('/0/404') + const res = getResObject() + + routerPrevious.lookup(req, res) + }) + bench('Error URL', () => { + const req = getReqObject('/0/error') + const res = getResObject() + + routerPrevious.lookup(req, res) + }) + }) + + run({ + silent: false, + avg: true, + json: false, + colors: true, + min_max: false, + percentiles: false + }) +}) diff --git a/lib/next.js b/lib/next.js index aeadfc2..bc560cb 100644 --- a/lib/next.js +++ b/lib/next.js @@ -1,8 +1,7 @@ function next (middlewares, req, res, index, routers, defaultRoute, errorHandler) { routers = routers || {} - const middleware = middlewares[index] - if (!middleware) { + if (index >= middlewares.length) { if (!res.finished) { return defaultRoute(req, res) } @@ -10,11 +9,13 @@ function next (middlewares, req, res, index, routers, defaultRoute, errorHandler return } + const middleware = middlewares[index++] + function step (err) { if (err) { return errorHandler(err, req, res) } else { - return next(middlewares, req, res, index + 1, routers, defaultRoute, errorHandler) + return next(middlewares, req, res, index, routers, defaultRoute, errorHandler) } } diff --git a/lib/router/sequential.js b/lib/router/sequential.js index 88edbef..538e53b 100644 --- a/lib/router/sequential.js +++ b/lib/router/sequential.js @@ -1,6 +1,6 @@ const Trouter = require('trouter') const next = require('./../next') -const LRU = require('lru-cache') +const { LRUCache: LRU } = require('lru-cache') const { parse } = require('regexparam') const queryparams = require('../utils/queryparams') @@ -70,7 +70,7 @@ module.exports = (config = {}) => { match = router.find(req.method, req.path) } - if (match.handlers.length !== 0) { + if (match.handlers.length > 0) { const middlewares = [...match.handlers] if (step !== undefined) { // router is being used as a nested router diff --git a/lib/utils/queryparams.js b/lib/utils/queryparams.js index f3f7f29..0909264 100644 --- a/lib/utils/queryparams.js +++ b/lib/utils/queryparams.js @@ -1,13 +1,17 @@ module.exports = (req, url) => { - const [path, search = ''] = url.split('?') - const searchParams = new URLSearchParams(search.replace(/\[\]=/g, '=')) - const query = {} - for (const [name, value] of searchParams.entries()) { - if (query[name]) { - Array.isArray(query[name]) ? query[name].push(value) : (query[name] = [query[name], value]) - } else { - query[name] = value + const indexOfQuestionMark = url.indexOf('?') + const path = indexOfQuestionMark !== -1 ? url.slice(0, indexOfQuestionMark) : url + const search = indexOfQuestionMark !== -1 ? url.slice(indexOfQuestionMark + 1) : '' + + if (search.length > 0) { + const searchParams = new URLSearchParams(search.replace(/\[\]=/g, '=')) + for (const [name, value] of searchParams.entries()) { + if (query[name]) { + Array.isArray(query[name]) ? query[name].push(value) : (query[name] = [query[name], value]) + } else { + query[name] = value + } } } diff --git a/package.json b/package.json index 580ec40..24d0aaa 100644 --- a/package.json +++ b/package.json @@ -27,12 +27,14 @@ }, "homepage": "https://github.com/BackendStack21/0http#readme", "devDependencies": { + "0http": "^3.5.2", "@types/node": "^18.14.4", "body-parser": "^1.20.1", "chai": "^4.3.7", "cross-env": "^7.0.3", "find-my-way": "^5.2.0", - "mocha": "^10.2.0", + "mitata": "^0.1.11", + "mocha": "^10.4.0", "nyc": "^15.1.0", "supertest": "^6.3.3" }, @@ -45,8 +47,8 @@ "lib/" ], "dependencies": { - "lru-cache": "^7.18.1", - "regexparam": "^2.0.1", + "lru-cache": "^10.2.0", + "regexparam": "^3.0.0", "trouter": "^3.2.1" }, "types": "./index.d.ts"