import crypto from 'crypto' import assert from 'assert' import Benchmark from 'benchmarkjs-pretty' import { koaRouter1, koaRouter2 } from './router_koa.js' import { flaskaRouter1, flaskaRouter2 } from './router_flaska.js' import { expressRouter1, expressRouter2 } from './router_express.js' import * as consts from './const.js' let assertOk = true let testData = null consts.overrideDummy(function() { testData = assertOk }) function TestPromiseCreators() { let resolveTrue = Promise.resolve(true) let asyncFunc = async function() { let check = await resolveTrue if (check !== true) { throw new Error('false') } } return new Benchmark.default('test different promise creation methods') .add('new Promise()', function() { return new Promise((res, rej) => { try { resolveTrue.then(function(check) { res(check) }) } catch (err) { rej(err) } }) }) .add('new Promise() static', function() { return new Promise((res, rej) => { res(true) }) }) .add('new Promise() static with try catch', function() { return new Promise((res, rej) => { try { res(true) } catch (err) { rej(err) } }) }) .add('new Promise() static with one then()', function() { return new Promise((res, rej) => { res(true) }).then(function(check) { return check }) }) .add('Promise.resolve()', function() { return Promise.resolve().then(function() { return resolveTrue }).then(function(check) { return check }) }) .add('resolved promise one then()', function() { return resolveTrue.then(function(check) { return check }) }) .add('resolved promise but four then()', function() { return resolveTrue.then(function(check) { return check }) .then(function(item) { return item }) .then(function(item) { return item }) .then(function(item) { return item }) }) .add('resolved promise but twenty then()', function() { return resolveTrue.then(function(check) { if (check !== true) { throw new Error('false') } return true }) .then(function(item) { return item }) .then(function(item) { return item }) .then(function(item) { return item }) .then(function(item) { return item }) .then(function(item) { return item }) .then(function(item) { return item }) .then(function(item) { return item }) .then(function(item) { return item }) .then(function(item) { return item }) .then(function(item) { return item }) .then(function(item) { return item }) .then(function(item) { return item }) .then(function(item) { return item }) .then(function(item) { return item }) .then(function(item) { return item }) .then(function(item) { return item }) .then(function(item) { return item }) .then(function(item) { return item }) .then(function(item) { return item }) }) .add('async function()', async function() { let check = await resolveTrue if (check !== true) { throw new Error('false') } }) .run() .then(function() {}, function(e) { console.error('error:', e) process.exit(1) }) } function TestObjectAssign() { const base = { state: {}, log: { info: function() { }, warn: function() { }, error: function() { }, }, router1: flaskaRouter1, router2: flaskaRouter2, } const req = { test: 1, test2: 2, koa1: koaRouter1, koa2: koaRouter2, test: function() {}, } const res = { express1: expressRouter1, express2: expressRouter2, test: function() {}, } let propMaker = {} let propMakerAlt = {} Object.keys(base).forEach(function(key) { propMaker[key] = { enumerable: true, value: base[key], writable: true, configurable: true, } propMakerAlt[key] = { enumerable: true, value: base[key], writable: true, configurable: true, } }) propMakerAlt.req = { enumerable: true, get: function() { return req }, configurable: true, } propMakerAlt.res = { enumerable: true, get: function() { return res }, configurable: true, } function register1(ctx) { ctx.log = base.log } function register2(ctx) { ctx.router1 = flaskaRouter1 } function register3(ctx) { ctx.router2 = flaskaRouter2 } function registerHeader(ctx) { ctx.headers['Server'] = 'nginx/1.16.1' ctx.headers['Date'] = 'Mon, 21 Mar 2022 07:26:01 GMT' ctx.headers['Content-Type'] = 'application/json; charset=utf-8' ctx.headers['Content-Length'] = '1646' ctx.headers['Connection'] = 'keep-alive' ctx.headers['vary'] = 'Origin' ctx.headers['Link'] = '; rel="current"; title="Page 1"' ctx.headers['pagination_total'] = '7' ctx.headers['X-Frame-Options'] = 'DENY' ctx.headers['X-Content-Type-Options'] = 'nosniff' } function registerHeaderAlt(ctx) { ctx.headers = { 'Server': 'nginx/1.16.1', 'Date': 'Mon, 21 Mar 2022 07:26:01 GMT', 'Content-Type': 'application/json; charset=utf-8', 'Content-Length': '1646', 'Connection': 'keep-alive', 'vary': 'Origin', 'Link': '; rel="current"; title="Page 1"', 'pagination_total': '7', 'X-Frame-Options': 'DENY', 'X-Content-Type-Options': 'nosniff', } } let baseHeaders = { 'Server': 'nginx/1.16.1', 'Date': 'Mon, 21 Mar 2022 07:26:01 GMT', 'Content-Type': 'application/json; charset=utf-8', 'Content-Length': '1646', 'Connection': 'keep-alive', 'vary': 'Origin', 'Link': '; rel="current"; title="Page 1"', 'pagination_total': '7', 'X-Frame-Options': 'DENY', 'X-Content-Type-Options': 'nosniff', } let keys = Object.keys(baseHeaders) return new Benchmark.default('test different method to initialize objects)') .add('[HEADERS] Object.assign()', function() { let ctx = { headers: {} } Object.assign(ctx.headers, baseHeaders) // assert.notStrictEqual(ctx.headers, baseHeaders) }) .add('[HEADERS] ecmascript spread', function() { let ctx = { headers: { ...baseHeaders } } // assert.notStrictEqual(ctx.headers, baseHeaders) }) .add('[HEADERS] Basic clone lol', function() { let ctx = { headers: {} } for (let key of keys) { ctx.headers[key] = baseHeaders[key] } // assert.notStrictEqual(ctx.headers, baseHeaders) }) .add('[HEADERS] Use register function', function() { let ctx = { headers: {} } registerHeader(ctx) // assert.notStrictEqual(ctx.headers, baseHeaders) }) .add('[HEADERS] Use register function ALT', function() { let ctx = { headers: {} } registerHeaderAlt(ctx) // assert.notStrictEqual(ctx.headers, baseHeaders) }) /* .add('Object.assign()', function() { let ctx = { req: req, res: res, } Object.assign(ctx, base) ctx.log.info() }) .add('register functions with direct assignment', function() { let ctx = { state: {}, req: req, res: res, } register1(ctx) register2(ctx) register3(ctx) ctx.log.info() }) .add('Object.create() all props', function() { let ctx = Object.create({}, propMakerAlt) ctx.log.info() }) .add('Object.defineProperties()', function() { let ctx = { req: req, res: res, } Object.defineProperties(ctx, propMaker) ctx.log.info() }) .add('Object.defineProperties() all props', function() { let ctx = { } Object.defineProperties(ctx, propMakerAlt) ctx.log.info() }) */ .run() .then(function() {}, function(e) { console.error('error:', e) process.exit(1) }) } function TestGenerateRandomString() { return new Benchmark.default('test different method to generate random string)') .add('crypto.randomBytes(16)', function() { for (let i = 0; i < 25; i++) { crypto.randomBytes(16).toString('base64') } }) .add('crypto.randomBytes(32)', function() { for (let i = 0; i < 25; i++) { crypto.randomBytes(32).toString('base64') } }) .add('random (22 characters long)', function() { for (let i = 0; i < 25; i++) { let out = Math.random().toString(36).substring(2, 24) + Math.random().toString(36).substring(2, 24) } }) .add('random (44 characters long)', function() { for (let i = 0; i < 25; i++) { let out = Math.random().toString(36).substring(2, 24) + Math.random().toString(36).substring(2, 24) + Math.random().toString(36).substring(2, 24) + Math.random().toString(36).substring(2, 24) } }) .run() .then(function() {}, function(e) { console.error('error:', e) process.exit(1) }) } function TestArrayReduce() { return new Benchmark.default('test different method to reduce array)') .add('currIndex', function() { const arr1 = new Array(100) for (let i = 0; i < arr1.length; i++) { arr1[i] = 'a' } let currIndex = arr1.length - 1 let out = '' while (currIndex >= 0) { out += arr1[currIndex] currIndex-- } }) .add('crypto.randomBytes(32)', function() { const arr1 = new Array(100) for (let i = 0; i < arr1.length; i++) { arr1[i] = 'a' } let out = '' while (arr1.length > 0) { out += arr1.splice(0, 1)[0] } }) .run() .then(function() {}, function(e) { console.error('error:', e) process.exit(1) }) } function TestStringCombination() { let val1 = 'some' let val2 = 'text' let val3 = 'gose' let val4 = 'here' return new Benchmark.default('test different method to combine string)') .add('ES6 with variable', function() { let out = `Hello my friend ${val1} this goes to ${val2} all my homies ${val3} over at my ${val4} house` return out }) .add('String concatenation', function() { let out = 'Hello my friend ' + val1 + ' this goes to ' + val2 + ' all my homies ' + val3 + ' over at my ' + val4 + ' house' return out }) .run() .then(function() {}, function(e) { console.error('error:', e) process.exit(1) }) } function TestSmallStaticRoute() { return new Benchmark.default('Small router static route benchmark: /api/staff (16 routes registered)') .add('expressjs', function() { testData = null expressRouter1.handle({ url: '/api/staff', method: 'GET', }, {}, function() { }) assert.ok(testData) }) .add('koa-router', function() { testData = koaRouter1.match('/api/staff', 'GET') assert.ok(testData.route) }) .add('bottle-router', function() { testData = flaskaRouter1.match('/api/staff') assert.ok(testData.handler) }) .run() .then(function() {}, function(e) { console.error('error:', e) process.exit(1) }) } function TestSmallParamRoute() { return new Benchmark.default('Small router param route benchmark: /api/staff/:id (16 routes registered)') .add('expressjs', function() { testData = null expressRouter1.handle({ url: '/api/staff/justatest', method: 'GET', }, {}, function() { }) assert.ok(testData) }) .add('koa-router', function() { testData = koaRouter1.match('/api/staff/justatest', 'GET') assert.ok(testData.route) }) .add('bottle-router', function() { testData = flaskaRouter1.match('/api/staff/justatest') assert.ok(testData.handler) }) .run() .then(function() {}, function(e) { console.error('error:', e) process.exit(1) }) } function TestLargeStaticRoute() { return new Benchmark.default('Large router static route benchmark: /api/staff (58 routes registered)') .add('expressjs', function() { testData = null expressRouter2.handle({ url: '/api/staff', method: 'GET', }, {}, function() { }) assert.ok(testData) }) .add('koa-router', function() { testData = koaRouter2.match('/api/staff', 'GET') assert.ok(testData.route) }) .add('bottle-router', function() { testData = flaskaRouter2.match('/api/staff') assert.ok(testData.handler) }) .run() .then(function() {}, function(e) { console.error('error:', e) process.exit(1) }) } function TestLargeParamRoute() { return new Benchmark.default('Large router param route benchmark: /api/staff/:id (58 routes registered)') .add('expressjs', function() { testData = null expressRouter2.handle({ url: '/api/staff/justatest', method: 'GET', }, {}, function() { }) assert.ok(testData) }) .add('koa-router', function() { testData = koaRouter2.match('/api/staff/justatest', 'GET') assert.ok(testData.route) }) .add('bottle-router', function() { testData = flaskaRouter2.match('/api/staff/justatest') assert.ok(testData.handler) }) .run() .then(function() {}, function(e) { console.error('error:', e) process.exit(1) }) } function TestLargeParamLargeUrlRoute() { return new Benchmark.default('Large router param route long route benchmark: /api/products/:id/sub_products/:productId (58 routes registered)') .add('expressjs', function() { testData = null expressRouter2.handle({ url: '/api/products/justatest/sub_products/foobar', method: 'GET', }, {}, function() { }) assert.ok(testData) }) .add('koa-router', function() { testData = koaRouter2.match('/api/products/justatest/sub_products/foobar', 'GET') assert.ok(testData.route) }) .add('bottle-router', function() { testData = flaskaRouter2.match('/api/products/justatest/sub_products/foobar') assert.ok(testData.handler) }) .run() .then(function() {}, function(e) { console.error('error:', e) process.exit(1) }) } /* TestSmallStaticRoute() // TestPromiseCreators() .then(function() { return TestSmallParamRoute() }) .then(function() { return TestLargeStaticRoute() }) .then(function() { return TestLargeParamRoute() }) .then(function() { return TestLargeParamLargeUrlRoute() }) .then(function() { process.exit(0) })*/ // TestObjectAssign() // TestGenerateRandomString() // TestArrayReduce() TestStringCombination() .then(function() { process.exit(0) })