From 57bc9cdfee4b06d612acd2f52cf09020a9981413 Mon Sep 17 00:00:00 2001 From: Trygve Lie Date: Fri, 15 Mar 2019 19:27:31 +0100 Subject: [PATCH] Improve creation performance of HttpIncoming --- .eslintrc | 1 + benchmark/benchmark.js | 50 ++++++++++++ lib/http-incoming.js | 176 ++++++++++++++++++++++++----------------- package.json | 16 ++-- 4 files changed, 165 insertions(+), 78 deletions(-) create mode 100644 benchmark/benchmark.js diff --git a/.eslintrc b/.eslintrc index b3eea94..18479ea 100644 --- a/.eslintrc +++ b/.eslintrc @@ -14,6 +14,7 @@ "plugins": ["prettier"], "root": true, "rules": { + "no-underscore-dangle": [0], "class-methods-use-this": [0], "strict": [0, "global"] } diff --git a/benchmark/benchmark.js b/benchmark/benchmark.js new file mode 100644 index 0000000..5163397 --- /dev/null +++ b/benchmark/benchmark.js @@ -0,0 +1,50 @@ +'use strict'; + +/* eslint no-unused-vars: "off", import/no-extraneous-dependencies: "off", no-console: "off" */ + +const benchmark = require('benchmark'); +const HttpIncoming = require('../lib/http-incoming'); + +const suite = new benchmark.Suite(); + +const add = (name, fn) => { + suite.add(name, fn); +}; + +/** + * new HttpIncoming(); + */ + +const REQ = { + headers: { + host: 'localhost:3030', + }, + hostname: 'localhost', + url: '/some/path', +}; + +const RES = { + locals: {}, +}; + +const PARAMS = { + foo: 'bar', +}; + +add('new HttpIncoming() - No params', () => { + const incoming = new HttpIncoming(REQ, RES); +}); + +add('new HttpIncoming() - With params', () => { + const incoming = new HttpIncoming(REQ, RES, PARAMS); +}); + +suite + .on('cycle', (ev) => { + console.log(ev.target.toString()); + if (ev.target.error) { + console.error(ev.target.error); + } + }) + .run(); + diff --git a/lib/http-incoming.js b/lib/http-incoming.js index db8d8f3..baa61c8 100644 --- a/lib/http-incoming.js +++ b/lib/http-incoming.js @@ -3,84 +3,114 @@ const originalUrl = require('original-url'); const { URL } = require('url'); +const _development = Symbol('podium:httpincoming:development'); +const _response = Symbol('podium:httpincoming:response'); +const _request = Symbol('podium:httpincoming:request'); +const _context = Symbol('podium:httpincoming:context'); +const _params = Symbol('podium:httpincoming:params'); +const _view = Symbol('podium:httpincoming:view'); +const _name = Symbol('podium:httpincoming:name'); +const _url = Symbol('podium:httpincoming:url'); +const _css = Symbol('podium:httpincoming:css'); +const _js = Symbol('podium:httpincoming:js'); + const noop = str => str; const PodiumHttpIncoming = class PodiumHttpIncoming { constructor(request = {}, response = {}, params = {}) { - Object.defineProperty(this, 'request', { - enumerable: true, - set() { - throw new Error('Cannot set read-only property.'); - }, - get() { - return request; - }, - }); - - Object.defineProperty(this, 'response', { - enumerable: true, - set() { - throw new Error('Cannot set read-only property.'); - }, - get() { - return response; - }, - }); - const url = originalUrl(request); - Object.defineProperty(this, 'url', { - enumerable: true, - value: url.full ? new URL(url.full) : {}, - }); - - Object.defineProperty(this, 'params', { - enumerable: true, - value: params, - }); - - Object.defineProperty(this, 'context', { - enumerable: true, - writable: true, - value: {}, - }); - - Object.defineProperty(this, 'development', { - enumerable: true, - writable: true, - value: false, - }); - - let view = noop; - Object.defineProperty(this, 'view', { - set(value) { - view = value; - }, - get() { - return view; - }, - }); - - Object.defineProperty(this, 'name', { - enumerable: true, - writable: true, - value: '', - }); - - Object.defineProperty(this, 'css', { - enumerable: true, - writable: true, - value: '', - }); - - Object.defineProperty(this, 'js', { - enumerable: true, - writable: true, - value: '', - }); + + // Private properties + this[_development] = false; + this[_response] = response; + this[_request] = request; + this[_context] = {}; + this[_params] = params; + this[_name] = ''; + this[_view] = noop; + this[_url] = url.full ? new URL(url.full) : {}; + this[_css] = ''; + this[_js] = ''; } - get [Symbol.toStringTag]() { - return 'PodiumHttpIncoming'; + set development(value) { + this[_development] = value; + } + + get development() { + return this[_development]; + } + + set response(value) { + throw new Error('Cannot set read-only property.'); + } + + get response() { + return this[_response]; + } + + set request(value) { + throw new Error('Cannot set read-only property.'); + } + + get request() { + return this[_request]; + } + + set context(value) { + this[_context] = value; + } + + get context() { + return this[_context]; + } + + set params(value) { + throw new Error('Cannot set read-only property.'); + } + + get params() { + return this[_params]; + } + + set name(value) { + this[_name] = value; + } + + get name() { + return this[_name]; + } + + set view(value) { + this[_view] = value; + } + + get view() { + return this[_view]; + } + + set url(value) { + throw new Error('Cannot set read-only property.'); + } + + get url() { + return this[_url]; + } + + set css(value) { + this[_css] = value; + } + + get css() { + return this[_css]; + } + + set js(value) { + this[_js] = value; + } + + get js() { + return this[_js]; } render(fragment) { @@ -101,6 +131,10 @@ const PodiumHttpIncoming = class PodiumHttpIncoming { js: this.js, }; } + + get [Symbol.toStringTag]() { + return 'PodiumHttpIncoming'; + } }; module.exports = PodiumHttpIncoming; diff --git a/package.json b/package.json index ec28525..5950672 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,8 @@ "lint:fix": "eslint --fix .", "test": "jest", "test:verbose": "jest --verbose", - "test:coverage": "jest --coverage" + "test:coverage": "jest --coverage", + "bench": "node benchmark/benchmark.js" }, "jest": { "coveragePathIgnorePatterns": [ @@ -43,16 +44,17 @@ "testEnvironment": "node" }, "devDependencies": { - "eslint": "^5.6.1", + "eslint": "^5.15.1", "eslint-config-airbnb-base": "^13.1.0", "eslint-config-prettier": "^4.1.0", - "eslint-plugin-import": "^2.14.0", + "eslint-plugin-import": "^2.16.0", "eslint-plugin-prettier": "^3.0.0", - "jest": "^23.6.0", - "prettier": "^1.14.2" + "jest": "^24.5.0", + "prettier": "^1.16.4", + "benchmark": "^2.1.4" }, "dependencies": { - "original-url": "^1.2.1", - "camelcase": "^5.0.0" + "camelcase": "^5.2.0", + "original-url": "^1.2.1" } }