├── .gitignore ├── JavaScript ├── debug.sh ├── 4-array.sh ├── 9-for-in.sh ├── Modularity │ ├── modularity.sh │ ├── lib2 │ │ ├── submodule1.js │ │ └── submodule2.js │ ├── lib3 │ │ ├── submodule1.js │ │ └── submodule2.js │ ├── lib0 │ │ ├── submodule1.js │ │ └── submodule2.js │ ├── lib1 │ │ ├── submodule1.js │ │ └── submodule2.js │ └── modularity.js ├── a-tick.sh ├── c-repeat.sh ├── 7-includes.sh ├── 8-for-let.sh ├── b-es6-map.sh ├── 5-range.sh ├── d-copy-array.sh ├── f-for-of-each.sh ├── e-copy-dataset.sh ├── 3-instantiation.sh ├── 6-functions.sh ├── c-repeat.js ├── a-tick.js ├── NodeOptimization │ ├── matchKnownFields.sh │ ├── matchKnownFields2.js │ ├── matchKnownFields3.js │ ├── matchKnownFields1.js │ └── matchKnownFields4.js ├── 8-for-let.js ├── 7-includes.js ├── 1-console-time.js ├── d-copy-array.js ├── e-copy-dataset.js ├── f-for-of-each.js ├── 9-for-in.js ├── 5-range.js ├── 6-functions.js ├── 3-instantiation.js ├── b-es6-map.js ├── 4-array.js └── 2-benchmark.js ├── .eslintignore ├── .editorconfig ├── LICENSE ├── README.md └── .eslintrc.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /JavaScript/debug.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | node --inspect $1 4 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | JavaScript/2-benchmark.js 3 | 4 | -------------------------------------------------------------------------------- /JavaScript/4-array.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | node --allow-natives-syntax --nouse-idle-notification 4-array 3 | -------------------------------------------------------------------------------- /JavaScript/9-for-in.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | node --allow-natives-syntax --nouse-idle-notification 9-for-in 3 | -------------------------------------------------------------------------------- /JavaScript/Modularity/modularity.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | node --allow-natives-syntax modularity.js 4 | -------------------------------------------------------------------------------- /JavaScript/a-tick.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | node --allow-natives-syntax --nouse-idle-notification a-tick 3 | -------------------------------------------------------------------------------- /JavaScript/c-repeat.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | node --allow-natives-syntax --nouse-idle-notification c-repeat 3 | -------------------------------------------------------------------------------- /JavaScript/7-includes.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | node --allow-natives-syntax --nouse-idle-notification 7-includes 3 | -------------------------------------------------------------------------------- /JavaScript/8-for-let.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | node --allow-natives-syntax --nouse-idle-notification 8-for-let 3 | -------------------------------------------------------------------------------- /JavaScript/b-es6-map.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | node --allow-natives-syntax --nouse-idle-notification b-es6-map 3 | -------------------------------------------------------------------------------- /JavaScript/5-range.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | node --allow-natives-syntax --nouse-idle-notification --expose-gc 5-range 3 | -------------------------------------------------------------------------------- /JavaScript/d-copy-array.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | node --allow-natives-syntax --nouse-idle-notification d-copy-array 3 | -------------------------------------------------------------------------------- /JavaScript/f-for-of-each.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | node --allow-natives-syntax --nouse-idle-notification f-for-of-each 3 | -------------------------------------------------------------------------------- /JavaScript/e-copy-dataset.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | node --allow-natives-syntax --nouse-idle-notification e-copy-dataset 3 | -------------------------------------------------------------------------------- /JavaScript/3-instantiation.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | node --allow-natives-syntax --nouse-idle-notification --expose-gc 3-instantiation 3 | -------------------------------------------------------------------------------- /JavaScript/6-functions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | node --allow-natives-syntax --nouse-idle-notification --expose-gc --noconcurrent_sweeping --noconcurrent_recompilation --predictable 6-functions 3 | -------------------------------------------------------------------------------- /JavaScript/Modularity/lib2/submodule1.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const moduleName = {}; 4 | module.exports = moduleName; 5 | 6 | moduleName.first = (value) => value; 7 | 8 | moduleName.second = (value) => value; 9 | -------------------------------------------------------------------------------- /JavaScript/Modularity/lib2/submodule2.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const moduleName = {}; 4 | module.exports = moduleName; 5 | 6 | moduleName.third = (value) => value; 7 | 8 | moduleName.fourth = (value) => value; 9 | -------------------------------------------------------------------------------- /JavaScript/Modularity/lib3/submodule1.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = (api) => { 4 | 5 | api.moduleName.first = (value) => value; 6 | 7 | api.moduleName.second = (value) => value; 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /JavaScript/Modularity/lib3/submodule2.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = (api) => { 4 | 5 | api.moduleName.third = (value) => value; 6 | 7 | api.moduleName.fourth = (value) => value; 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /JavaScript/Modularity/lib0/submodule1.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | 5 | first(value) { 6 | return value; 7 | }, 8 | 9 | second(value) { 10 | return value; 11 | } 12 | 13 | }; 14 | -------------------------------------------------------------------------------- /JavaScript/Modularity/lib0/submodule2.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | 5 | third(value) { 6 | return value; 7 | }, 8 | 9 | fourth(value) { 10 | return value; 11 | } 12 | 13 | }; 14 | -------------------------------------------------------------------------------- /JavaScript/Modularity/lib1/submodule1.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function first(value) { 4 | return value; 5 | } 6 | 7 | function second(value) { 8 | return value; 9 | } 10 | 11 | module.exports = { first, second }; 12 | -------------------------------------------------------------------------------- /JavaScript/Modularity/lib1/submodule2.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function third(value) { 4 | return value; 5 | } 6 | 7 | function fourth(value) { 8 | return value; 9 | } 10 | 11 | module.exports = { third, fourth }; 12 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | end_of_line = lf 6 | charset = utf-8 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | 10 | [{*.js,*.mjs,*.ts,*.json,*.yml}] 11 | indent_size = 2 12 | indent_style = space 13 | -------------------------------------------------------------------------------- /JavaScript/c-repeat.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const benchmark = require('./2-benchmark.js'); 4 | 5 | const testArrayJoin = () => Array(20).join('.'); 6 | const testRepeat = () => '.'.repeat(20); 7 | 8 | benchmark.do(1000000, [ 9 | testArrayJoin, 10 | testRepeat, 11 | ]); 12 | -------------------------------------------------------------------------------- /JavaScript/a-tick.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const benchmark = require('./2-benchmark.js'); 4 | 5 | const testConcat = () => 'Hello user' + parseInt('5') * 10 + ' !'; 6 | 7 | const testTick = () => `Hello user${parseInt('5') * 10} !`; 8 | 9 | benchmark.do(10000000, [ 10 | testConcat, 11 | testTick, 12 | ]); 13 | -------------------------------------------------------------------------------- /JavaScript/NodeOptimization/matchKnownFields.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | node --allow-natives-syntax --nouse-idle-notification matchKnownFields1.js 4 | node --allow-natives-syntax --nouse-idle-notification matchKnownFields2.js 5 | node --allow-natives-syntax --nouse-idle-notification matchKnownFields3.js 6 | node --allow-natives-syntax --nouse-idle-notification matchKnownFields4.js 7 | -------------------------------------------------------------------------------- /JavaScript/8-for-let.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const benchmark = require('./2-benchmark.js'); 4 | 5 | function testLetBeforeLoop() { 6 | const a = Array(1000); 7 | let i; 8 | for (i = 0; i < 1000; i++) { 9 | a[i] = i; 10 | } 11 | } 12 | 13 | function testLetInLoop() { 14 | const a = Array(1000); 15 | for (let i = 0; i < 1000; i++) { 16 | a[i] = i; 17 | } 18 | } 19 | 20 | benchmark.do(1000000, [ 21 | testLetInLoop, 22 | testLetBeforeLoop 23 | ]); 24 | -------------------------------------------------------------------------------- /JavaScript/7-includes.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const benchmark = require('./2-benchmark.js'); 4 | 5 | const data = ['abc', 'defg', 'hijklmn', 'opqrst', 'u', 'v', 'xyz']; 6 | 7 | function testIndexOf() { 8 | return [ 9 | data.indexOf('opqrst') !== -1, 10 | data.indexOf('qwerty') !== -1, 11 | data.indexOf('v') !== -1 12 | ]; 13 | } 14 | 15 | function testIncludes() { 16 | return [ 17 | data.includes('opqrst'), 18 | data.includes('qwerty'), 19 | data.includes('v') 20 | ]; 21 | } 22 | 23 | benchmark.do(10000000, [ 24 | testIncludes, 25 | testIndexOf 26 | ]); 27 | -------------------------------------------------------------------------------- /JavaScript/1-console-time.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const LOOP_COUNT = 50000; 4 | 5 | const fn = () => { 6 | const a = []; 7 | for (let i = 0; i < LOOP_COUNT; i++) { 8 | a.push(Array(i).join('A').length); 9 | } 10 | return a; 11 | }; 12 | 13 | console.log(); 14 | 15 | console.time('experiment'); 16 | const res1 = fn(); 17 | console.log('res1.length', res1.length); 18 | console.timeEnd('experiment'); 19 | 20 | console.log(); 21 | 22 | const begin2 = new Date().getTime(); 23 | const res2 = fn(); 24 | const end2 = new Date().getTime(); 25 | const diff2 = end2 - begin2; 26 | console.dir({ length: res2.length, diff: diff2 }); 27 | 28 | console.log(); 29 | 30 | const begin3 = process.hrtime(); 31 | const res3 = fn(); 32 | const end3 = process.hrtime(begin3); 33 | const diff3 = end3[0] * 1e9 + end3[1]; 34 | const sec3 = diff3 / 1e9; 35 | console.dir({ length: res3.length, msec: diff3, sec: sec3 }); 36 | -------------------------------------------------------------------------------- /JavaScript/d-copy-array.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const benchmark = require('./2-benchmark.js'); 4 | 5 | // Prepare data 6 | 7 | const arr = []; 8 | for (let i = 0; i < 100; i++) { 9 | arr[i] = (i - 50) * i; 10 | } 11 | 12 | // Different implementations 13 | 14 | const testSlice = () => arr.slice(); 15 | 16 | const testSlice0 = () => arr.slice(0); 17 | 18 | const testConcat = () => [].concat(arr); 19 | 20 | const testFor = () => { 21 | const result = []; 22 | for (let i = 0; i < arr.length; i++) { 23 | result.push(arr[i]); 24 | } 25 | return result; 26 | }; 27 | 28 | const testForNew = () => { 29 | const len = arr.length; 30 | const result = new Array(len); 31 | for (let i = 0; i < len; i++) { 32 | result[i] = arr[i]; 33 | } 34 | return result; 35 | }; 36 | 37 | // Run tests 38 | 39 | benchmark.do(500000, [ 40 | testSlice, 41 | testSlice0, 42 | testConcat, 43 | testFor, 44 | testForNew, 45 | ]); 46 | -------------------------------------------------------------------------------- /JavaScript/e-copy-dataset.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const benchmark = require('./2-benchmark.js'); 4 | 5 | // Prepare data 6 | 7 | const arr = []; 8 | for (let i = 0; i < 100; i++) { 9 | arr[i] = { name: 'item' + ((i - 50) * i) }; 10 | } 11 | 12 | // Different implementations 13 | 14 | const testSlice = () => arr.slice(); 15 | 16 | const testSlice0 = () => arr.slice(0); 17 | 18 | const testConcat = () => [].concat(arr); 19 | 20 | const testFor = () => { 21 | const result = []; 22 | for (let i = 0; i < arr.length; i++) { 23 | result.push(arr[i]); 24 | } 25 | return result; 26 | }; 27 | 28 | const testForNew = () => { 29 | const len = arr.length; 30 | const result = new Array(len); 31 | for (let i = 0; i < len; i++) { 32 | result[i] = arr[i]; 33 | } 34 | return result; 35 | }; 36 | 37 | // Run tests 38 | 39 | benchmark.do(500000, [ 40 | testSlice, 41 | testSlice0, 42 | testConcat, 43 | testFor, 44 | testForNew, 45 | ]); 46 | -------------------------------------------------------------------------------- /JavaScript/f-for-of-each.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const benchmark = require('./2-benchmark.js'); 4 | 5 | const data1 = [ 6 | -100, -50, -30, -20, -10, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 7 | ]; 8 | 9 | const data2 = [ 10 | 'Descartes', 'Pascal', 'Leibniz', 'Euler', 'Bernoulli', 'Kepler' 11 | ]; 12 | 13 | const testEachNumber = () => { 14 | const a = Array(data1.length); 15 | data1.forEach((item, i) => { 16 | a[i] = data1[i]; 17 | }); 18 | return a; 19 | }; 20 | 21 | const testForOfNumber = () => { 22 | const a = Array(data1.length); 23 | let i = 0; 24 | for (const n of data1) { 25 | a[i++] = n; 26 | } 27 | return a; 28 | }; 29 | 30 | const testEachString = () => { 31 | const a = Array(data2.length); 32 | data2.forEach((item, i) => { 33 | a[i] = data2[i]; 34 | }); 35 | return a; 36 | }; 37 | 38 | const testForOfString = () => { 39 | const a = Array(data2.length); 40 | let i = 0; 41 | for (const s of data2) { 42 | a[i++] = s; 43 | } 44 | return a; 45 | }; 46 | 47 | benchmark.do(5000000, [ 48 | testEachNumber, 49 | testForOfNumber, 50 | testEachString, 51 | testForOfString, 52 | ]); 53 | -------------------------------------------------------------------------------- /JavaScript/9-for-in.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const benchmark = require('./2-benchmark.js'); 4 | 5 | const data = { 6 | a: 'abc', 7 | bcd: 'defg', 8 | efgh: 'hijklmn', 9 | ijk: 'opqrst', 10 | lmnopqrs: 'u', 11 | tvuwx: 'v', 12 | yz: 'xyz' 13 | }; 14 | 15 | const testForKeys = () => { 16 | const a = Array(7); 17 | const keys = Object.keys(data); 18 | for (let i = 0; i < keys.length; i++) { 19 | const key = keys[i]; 20 | a[i] = data[key]; 21 | } 22 | }; 23 | 24 | const testForIn = () => { 25 | const a = Array(7); 26 | let i = 0; 27 | for (const key in data) { 28 | a[i++] = data[key]; 29 | } 30 | }; 31 | 32 | const testForEach = () => { 33 | const a = Array(7); 34 | let i = 0; 35 | const keys = Object.keys(data); 36 | keys.forEach((key) => { 37 | a[i++] = data[key]; 38 | }); 39 | }; 40 | 41 | const testForOf = () => { 42 | const a = Array(7); 43 | let i = 0; 44 | const keys = Object.keys(data); 45 | for (const key of keys) { 46 | const val = data[key]; 47 | a[i++] = val; 48 | } 49 | }; 50 | 51 | benchmark.do(10000000, [ 52 | testForKeys, 53 | testForIn, 54 | testForEach, 55 | testForOf, 56 | ]); 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-2023 How.Programming.Works contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /JavaScript/5-range.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const benchmark = require('./2-benchmark.js'); 4 | 5 | const rangePush = (min, max) => { 6 | const arr = []; 7 | for (let i = min; i <= max; i++) arr.push(i); 8 | return arr; 9 | }; 10 | 11 | const rangeNew = (from, to) => { 12 | if (to < from) return []; 13 | const len = to - from + 1; 14 | const range = new Array(len); 15 | for (let i = from; i <= to; i++) { 16 | range[i - from] = i; 17 | } 18 | return range; 19 | }; 20 | 21 | const rangeEx = (range) => { 22 | const from = range[0]; 23 | let to = range[1]; 24 | const toType = typeof to; 25 | if (toType === 'undefined') { 26 | to = range[2]; 27 | return api.common.range(from, to); 28 | } else if (toType !== 'number') { 29 | let count = to[0]; 30 | if (count < 0) { 31 | const cpus = api.os.cpus().length; 32 | count = cpus + count; 33 | } 34 | return api.common.range(from, from + count - 1); 35 | } 36 | return []; 37 | }; 38 | 39 | benchmark.do(1000000, [ 40 | function testRangePush() { 41 | rangePush(1, 1000); 42 | }, 43 | function testRangeNew() { 44 | rangeNew(1, 1000); 45 | }, 46 | function testRangeEx() { 47 | rangeEx(1, 1000); 48 | }, 49 | ]); 50 | -------------------------------------------------------------------------------- /JavaScript/6-functions.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const benchmark = require('./2-benchmark.js'); 4 | 5 | const fnLambdaBlock = () => {}; 6 | // eslint-disable-next-line 7 | const fnLambdaBlockU = () => { return; }; 8 | // eslint-disable-next-line 9 | const fnLambdaBlockN = () => { return null; }; 10 | // eslint-disable-next-line 11 | const fnLambdaBlock0 = () => { return 0; }; 12 | 13 | const fnLambdaExprU = () => undefined; 14 | const fnLambdaExprN = () => null; 15 | const fnLambdaExpr0 = () => 0; 16 | 17 | const fnExpression = function() {}; 18 | const fnExpressionU = function() { return; }; 19 | const fnExpressionN = function() { return null; }; 20 | const fnExpression0 = function() { return 0; }; 21 | 22 | function fnDeclaration() {} 23 | function fnDeclarationU() { return; } 24 | function fnDeclarationN() { return null; } 25 | function fnDeclaration0() { return 0; } 26 | 27 | benchmark.do(10000000, [ 28 | fnLambdaBlock, 29 | fnLambdaBlockU, 30 | fnLambdaBlockN, 31 | fnLambdaBlock0, 32 | fnLambdaExprU, 33 | fnLambdaExprN, 34 | fnLambdaExpr0, 35 | fnDeclaration, 36 | fnDeclarationU, 37 | fnDeclarationN, 38 | fnDeclaration0, 39 | fnExpression, 40 | fnExpressionU, 41 | fnExpressionN, 42 | fnExpression0 43 | ]); 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Измерение производительности кода и оптимизация 2 | =============== 3 | 4 | [![Измерение производительности кода и оптимизация](https://img.youtube.com/vi/sanq2X7Re8o/0.jpg)](https://www.youtube.com/watch?v=sanq2X7Re8o) 5 | 6 | ## Оптимизация 7 | - Объекты одинаковой структуры 8 | - Функции одинаковой формы (мономорфные) 9 | - Массивы одинаковых типов 10 | 11 | ## Замер скорости 12 | - Желательно проверять крупные алгоритмы или целые блоки 13 | - Одинаковые условия исполнения для каждой итерации теста 14 | - Единица оптимизации - функция, оборачиваем тестируемый код в функцию 15 | - Сохраняем результаты (вводим оптимизатор в заблуждение) 16 | - Прогрев кода перед тестом (дождаться стабилизации) 17 | - Может получиться инлайнинг функций (можно проверить руками) 18 | - Чтоб не инлайнило, например (можно добавить `try {}`) 19 | - Принимаем во внимание, что константы подставляются в выражения 20 | - Выражения могут быть предварительно вычислены (не на каждой итерации) 21 | - Вынесение инвариантов цикла (в цикле остается только то, на что влияет цикл) 22 | - Мертвый код (который мог бы быть выброшен оптимизатором) 23 | - Внетренние функции v8 `--allow-natives-syntax` 24 | - Отключение автоматического gc `--nouse-idle-notification` 25 | - Ручной gc `--expose-gc` 26 | - Выделение больше памяти `--max_old_space_size=2048` 27 | -------------------------------------------------------------------------------- /JavaScript/3-instantiation.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const benchmark = require('./2-benchmark.js'); 4 | 5 | const makeClosure = (hello, size, flag) => () => ( 6 | { hello, size, flag } 7 | ); 8 | 9 | const closureInstance = () => makeClosure('world', 100500, true); 10 | 11 | const defineArray = () => ['world', 100500, true]; 12 | 13 | const defineArrayOfString = () => ['world', 'world', 'world']; 14 | 15 | const defineArrayOfNumber = () => [100500, 100500, 100500]; 16 | 17 | const defineObject = () => ({ 18 | hello: 'world', 19 | size: 100500, 20 | flag: true 21 | }); 22 | 23 | const mixinObject = () => { 24 | const obj = {}; 25 | obj.hello = 'world'; 26 | obj.size = 100500; 27 | obj.flag = true; 28 | return obj; 29 | }; 30 | 31 | function ProtoItem(hello, size, flag) { 32 | this.hello = hello; 33 | this.size = size; 34 | this.flag = flag; 35 | } 36 | 37 | const newPrototype = () => new ProtoItem('world', 100500, true); 38 | 39 | const ClassItem = class { 40 | constructor(hello, size, flag) { 41 | this.hello = hello; 42 | this.size = size; 43 | this.flag = flag; 44 | } 45 | }; 46 | 47 | const newClass = () => new ClassItem('world', 100500, true); 48 | 49 | const newObject = () => { 50 | const obj = new Object(); 51 | obj.hello = 'world'; 52 | obj.size = 100500; 53 | obj.flag = true; 54 | return obj; 55 | }; 56 | 57 | const objectCreate = () => { 58 | const obj = Object.create(null); 59 | obj.hello = 'world'; 60 | obj.size = 100500; 61 | obj.flag = true; 62 | return obj; 63 | }; 64 | 65 | const itemFactory = (hello, size, flag) => ({ hello, size, flag }); 66 | 67 | const callFactory = () => itemFactory('world', 100500, true); 68 | 69 | benchmark.do(1000000, [ 70 | callFactory, 71 | closureInstance, 72 | defineObject, 73 | defineArray, 74 | defineArrayOfString, 75 | defineArrayOfNumber, 76 | mixinObject, 77 | newPrototype, 78 | newClass, 79 | newObject, 80 | objectCreate 81 | ]); 82 | -------------------------------------------------------------------------------- /JavaScript/b-es6-map.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const benchmark = require('./2-benchmark.js'); 4 | 5 | const cities = new Map(); 6 | cities.set('Athens', { name: 'Афины', population: 664046 }); 7 | cities.set('Rome', { name: 'Рим', population: 2627000 }); 8 | cities.set('London', { name: 'Лондон', population: 8674000 }); 9 | cities.set('Beijing', { name: 'Пекин', population: 11510000 }); 10 | cities.set('Kiev', { name: 'Киев', population: 2804000 }); 11 | cities.set('Riga', { name: 'Рига', population: 643615 }); 12 | 13 | const citiesOld = { 14 | Athens: { name: 'Афины', population: 664046 }, 15 | Rome: { name: 'Рим', population: 2627000 }, 16 | London: { name: 'Лондон', population: 8674000 }, 17 | Beijing: { name: 'Пекин', population: 11510000 }, 18 | Kiev: { name: 'Киев', population: 2804000 }, 19 | Riga: { name: 'Рига', population: 643615 } 20 | }; 21 | 22 | const testForInHash = () => { 23 | const arr = []; 24 | for (const key in citiesOld) { 25 | arr.push([ citiesOld[key], key ]); 26 | } 27 | }; 28 | 29 | const testForEach = () => { 30 | const arr = []; 31 | cities.forEach((value, key) => { 32 | arr.push([ value, key ]); 33 | }); 34 | }; 35 | 36 | const testForOf = () => { 37 | const arr = []; 38 | for (const [key, value] of cities) { 39 | arr.push([ value, key ]); 40 | } 41 | }; 42 | 43 | const testForOfKeys = () => { 44 | const arr = []; 45 | for (const key of cities.keys()) { 46 | arr.push(key); 47 | } 48 | }; 49 | 50 | const testForOfValues = () => { 51 | const arr = []; 52 | for (const value of cities.values()) { 53 | arr.push(value); 54 | } 55 | }; 56 | 57 | const testForOfEntries = () => { 58 | const arr = []; 59 | for (const [key, value] of cities.entries()) { 60 | arr.push([ key, value ]); 61 | } 62 | }; 63 | 64 | benchmark.do(1000000, [ 65 | testForInHash, 66 | testForEach, 67 | testForOf, 68 | testForOfKeys, 69 | testForOfValues, 70 | testForOfEntries, 71 | ]); 72 | -------------------------------------------------------------------------------- /JavaScript/Modularity/modularity.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const benchmark = require('../2-benchmark.js'); 4 | 5 | const test0api = { 6 | moduleName: { 7 | submodule1: require('./lib0/submodule1'), 8 | submodule2: require('./lib0/submodule2') 9 | } 10 | }; 11 | 12 | const test1api = { 13 | moduleName: { 14 | submodule1: require('./lib1/submodule1'), 15 | submodule2: require('./lib1/submodule2') 16 | } 17 | }; 18 | 19 | const test2api = { 20 | moduleName: { 21 | submodule1: require('./lib2/submodule1'), 22 | submodule2: require('./lib2/submodule2') 23 | } 24 | }; 25 | 26 | const test3api = {}; 27 | test3api.moduleName = {}; 28 | require('./lib3/submodule1')(test3api); 29 | require('./lib3/submodule2')(test3api); 30 | 31 | console.dir(test0api); 32 | console.dir(test1api); 33 | console.dir(test2api); 34 | console.dir(test3api); 35 | 36 | function exportObj() { 37 | const a = test0api.moduleName.submodule1.first('Value'); 38 | const b = test0api.moduleName.submodule1.second(a); 39 | const c = test0api.moduleName.submodule2.third(b); 40 | const d = test0api.moduleName.submodule2.fourth(c); 41 | return d; 42 | } 43 | 44 | function exportHash() { 45 | const a = test1api.moduleName.submodule1.first('Value'); 46 | const b = test1api.moduleName.submodule1.second(a); 47 | const c = test1api.moduleName.submodule2.third(b); 48 | const d = test1api.moduleName.submodule2.fourth(c); 49 | return d; 50 | } 51 | 52 | function exportLink() { 53 | const a = test2api.moduleName.submodule1.first('Value'); 54 | const b = test2api.moduleName.submodule1.second(a); 55 | const c = test2api.moduleName.submodule2.third(b); 56 | const d = test2api.moduleName.submodule2.fourth(c); 57 | return d; 58 | } 59 | 60 | function exportClosure() { 61 | const a = test3api.moduleName.first('Value'); 62 | const b = test3api.moduleName.second(a); 63 | const c = test3api.moduleName.third(b); 64 | const d = test3api.moduleName.fourth(c); 65 | return d; 66 | } 67 | 68 | benchmark.do(10000000, [ 69 | exportObj, 70 | exportHash, 71 | exportLink, 72 | exportClosure 73 | ]); 74 | -------------------------------------------------------------------------------- /JavaScript/4-array.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const benchmark = require('./2-benchmark.js'); 4 | 5 | // Define Data Source 6 | 7 | const data1 = [ 8 | { name: 'Marcus Aurelius', 9 | birth: new Date('212-04-26'), 10 | city: 'Rome' }, 11 | { name: 'Victor Glushkov', 12 | birth: new Date('1923-08-24'), 13 | city: 'Rostov on Don' }, 14 | { name: 'Ibn Arabi', 15 | birth: new Date('1165-11-16'), 16 | city: 'Murcia' }, 17 | { name: 'Mao Zedong', 18 | birth: new Date('1893-12-26'), 19 | city: 'Shaoshan' }, 20 | { name: 'Rene Descartes', 21 | birth: new Date('1596-03-31'), 22 | city: 'La Haye en Touraine' }, 23 | ]; 24 | 25 | const data2 = [ 26 | ['Marcus Aurelius', '212-04-26', 'Rome'], 27 | ['Victor Glushkov', '1923-08-24', 'Rostov on Don'], 28 | ['Ibn Arabi', '1165-11-16', 'Murcia'], 29 | ['Mao Zedong', '1893-12-26', 'Shaoshan'], 30 | ['Rene Descartes', '1596-03-31', 'La Haye en Touraine'] 31 | ]; 32 | 33 | const metadata = { 34 | name: 'string', 35 | birth: 'Date', 36 | city: 'string', 37 | age() { 38 | const difference = new Date() - this.birth; 39 | return Math.floor(difference / 31536000000); 40 | } 41 | }; 42 | 43 | // Prepare prototype 44 | 45 | function Person() {} 46 | 47 | let index = 0; 48 | for (const name in metadata) { 49 | buildGetter(Person.prototype, name, metadata[name], index++); 50 | } 51 | 52 | function buildGetter(proto, fieldName, fieldType, fieldIndex) { 53 | if (fieldType === 'Date') { 54 | Object.defineProperty(proto, fieldName, { 55 | get() { 56 | return new Date(this[fieldIndex]); 57 | } 58 | }); 59 | } else if (typeof fieldType === 'function') { 60 | Object.defineProperty(proto, fieldName, { get: fieldType }); 61 | } else { 62 | Object.defineProperty(proto, fieldName, { 63 | get() { 64 | return this[fieldIndex]; 65 | } 66 | }); 67 | } 68 | } 69 | 70 | data2.forEach((person) => Object.setPrototypeOf(person, Person.prototype)); 71 | //data2.forEach(person => person.__proto__ = Person.prototype); 72 | 73 | // Define query 74 | 75 | const query = (person) => ( 76 | person.name !== '' && 77 | person.age > 18 && 78 | person.city === 'Rome' 79 | ); 80 | 81 | // Execute tests 82 | 83 | benchmark.do(1000000, [ 84 | function filterObjects() { 85 | data1.filter(query); 86 | }, 87 | function filterArrays() { 88 | data2.filter(query); 89 | } 90 | ]); 91 | -------------------------------------------------------------------------------- /JavaScript/2-benchmark.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const benchmark = {}; 4 | module.exports = benchmark; 5 | 6 | const PRE_COUNT = 10000; 7 | 8 | const OPT_STATUS = [ 9 | /* 0 */ 'unknown', 10 | /* 1 */ 'opt', 11 | /* 2 */ 'not opt', 12 | /* 3 */ 'always opt', 13 | /* 4 */ 'never opt', 14 | /* 5 */ 'unknown', 15 | /* 6 */ 'maybe deopt', 16 | /* 7 */ 'turbofan opt' 17 | ]; 18 | 19 | const OPT_BITS = [ 20 | /* 1 */ 'function', 21 | /* 2 */ 'never', 22 | /* 4 */ 'always', 23 | /* 8 */ 'maybe', 24 | /* 16 */ 'opt', 25 | /* 32 */ 'turbofan', 26 | /* 64 */ 'interp' 27 | ]; 28 | 29 | const status = fn => %GetOptimizationStatus(fn); 30 | 31 | const opt = fn => { 32 | const optStatus = status(fn); 33 | const results = []; 34 | OPT_BITS.forEach((name, n) => { 35 | if (n === 0) return; 36 | if (Math.pow(2, n) & optStatus) results.push(name); 37 | }); 38 | return results.length ? results.join(', ') : 'no preopt,'; 39 | } 40 | 41 | const optimize = fn => %OptimizeFunctionOnNextCall(fn); 42 | 43 | const rpad = (s, char, count) => (s + char.repeat(count - s.length)); 44 | const lpad = (s, char, count) => (char.repeat(count - s.length) + s); 45 | 46 | const relativePercent = (best, time) => (time * 100n / best) - 100n; 47 | 48 | console.log('\nname time (nanoseconds) status: begin opt heat loop\n'); 49 | 50 | benchmark.do = (count, tests) => { 51 | const times = tests.map(fn => { 52 | if (global.gc) gc(); 53 | const result = []; 54 | const optBefore = opt(fn); 55 | optimize(fn); 56 | fn(); 57 | const optAfter = opt(fn); 58 | for (let i = 0; i < PRE_COUNT; i++) result.push(fn()); 59 | const optAfterHeat = opt(fn); 60 | const begin = process.hrtime.bigint(); 61 | for (let i = 0; i < count; i++) result.push(fn()); 62 | const end = process.hrtime.bigint(); 63 | const optAfterLoop = opt(fn); 64 | const diff = end - begin; 65 | const name = rpad(fn.name, '.', 22); 66 | const iterations = result.length - PRE_COUNT; 67 | const log = [ 68 | name, diff, optBefore, optAfter, optAfterHeat, optAfterLoop 69 | ]; 70 | console.log(log.join(' ')); 71 | return { name, time: diff }; 72 | }); 73 | console.log(); 74 | console.log(times); 75 | const top = times.sort((t1, t2) => t1.time > t2.time ? 1 : -1); 76 | const best = top[0].time; 77 | times.forEach(test => { 78 | test.percent = relativePercent(best, test.time); 79 | const time = lpad(test.time.toString(), '.', 10); 80 | const percent = test.percent === 0 ? 'min' : test.percent + '%'; 81 | const line = lpad(percent, '.', 10); 82 | console.log(test.name + time + line); 83 | }); 84 | }; 85 | -------------------------------------------------------------------------------- /JavaScript/NodeOptimization/matchKnownFields2.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const benchmark = require('../2-benchmark.js'); 4 | 5 | const HTTP_HDR_TO_LOWER = { 6 | 'Content-Type': 'content-type', 7 | 'Content-Length': 'content-length', 8 | 'User-Agent': 'user-agent', 9 | 'Referer': 'referer', 10 | 'Host': 'host', 11 | 'Authorization': 'authorization', 12 | 'Proxy-Authorization': 'proxy-authorization', 13 | 'If-Modified-Since': 'if-modified-since', 14 | 'If-Unmodified-Since': 'if-unmodified-since', 15 | 'From': 'from', 16 | 'Location': 'location', 17 | 'Max-Forwards': 'max-forwards', 18 | 'Retry-After': 'retry-after', 19 | 'ETag': 'etag', 20 | 'Last-Modified': 'last-modified', 21 | 'Server': 'server', 22 | 'Age': 'age', 23 | 'Expires': 'expires' 24 | }; 25 | 26 | { 27 | let key, value; 28 | for (key in HTTP_HDR_TO_LOWER) { 29 | value = HTTP_HDR_TO_LOWER[key]; 30 | HTTP_HDR_TO_LOWER[value] = value; 31 | } 32 | } 33 | 34 | HTTP_HDR_TO_LOWER['Set-Cookie'] = '\u0001'; 35 | HTTP_HDR_TO_LOWER['set-Cookie'] = '\u0001'; 36 | HTTP_HDR_TO_LOWER['Cookie'] = '\u0002cookie'; 37 | HTTP_HDR_TO_LOWER['cookie'] = '\u0002cookie'; 38 | 39 | const HTTP_HDR_TO_LOWER_0 = { 40 | 'Transfer-Encoding': 'transfer-encoding', 41 | 'Date': 'date', 42 | 'Connection': 'connection', 43 | 'Cache-Control': 'cache-control', 44 | 'Vary': 'vary', 45 | 'Content-Encoding': 'content-encoding', 46 | 'Origin': 'origin', 47 | 'Upgrade': 'upgrade', 48 | 'Expect': 'expect', 49 | 'If-Match': 'if-match', 50 | 'If-None-Match': 'if-none-match', 51 | 'Accept': 'accept', 52 | 'Accept-Encoding': 'accept-encoding', 53 | 'Accept-Language': 'accept-language', 54 | 'X-Forwarded-For': 'x-forwarded-for', 55 | 'X-Forwarded-Host': 'x-forwarded-host', 56 | 'X-Forwarded-Proto': 'x-forwarded-proto' 57 | }; 58 | 59 | { 60 | let key, value, data; 61 | for (key in HTTP_HDR_TO_LOWER_0) { 62 | value = HTTP_HDR_TO_LOWER_0[key]; 63 | data = '\u0000' + value; 64 | HTTP_HDR_TO_LOWER[key] = data; 65 | HTTP_HDR_TO_LOWER[value] = data; 66 | } 67 | } 68 | 69 | function matchKnownFields2(field) { 70 | let toLower; 71 | toLower = HTTP_HDR_TO_LOWER[field]; 72 | if (toLower) return toLower; 73 | field = field.toLowerCase(); 74 | toLower = HTTP_HDR_TO_LOWER[field]; 75 | if (toLower) return toLower; 76 | return '\u0000' + field; 77 | } 78 | 79 | function testMatchKnownFields2() { 80 | return [ 81 | matchKnownFields2('Authorization'), 82 | matchKnownFields2('if-unmodified-since'), 83 | matchKnownFields2('Content-Type'), 84 | matchKnownFields2('last-modified'), 85 | matchKnownFields2('X-Forwarded-For'), 86 | matchKnownFields2('accept'), 87 | matchKnownFields2('Cache-Control'), 88 | matchKnownFields2('cookie') 89 | ]; 90 | } 91 | 92 | 93 | benchmark.do(10000000, [testMatchKnownFields2]); 94 | -------------------------------------------------------------------------------- /JavaScript/NodeOptimization/matchKnownFields3.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const benchmark = require('../2-benchmark.js'); 4 | 5 | const HTTP_HDR_TO_LOWER = { 6 | 'Content-Type': 'content-type', 7 | 'Content-Length': 'content-length', 8 | 'User-Agent': 'user-agent', 9 | 'Referer': 'referer', 10 | 'Host': 'host', 11 | 'Authorization': 'authorization', 12 | 'Proxy-Authorization': 'proxy-authorization', 13 | 'If-Modified-Since': 'if-modified-since', 14 | 'If-Unmodified-Since': 'if-unmodified-since', 15 | 'From': 'from', 16 | 'Location': 'location', 17 | 'Max-Forwards': 'max-forwards', 18 | 'Retry-After': 'retry-after', 19 | 'ETag': 'etag', 20 | 'Last-Modified': 'last-modified', 21 | 'Server': 'server', 22 | 'Age': 'age', 23 | 'Expires': 'expires' 24 | }; 25 | 26 | { 27 | let key, value; 28 | for (key in HTTP_HDR_TO_LOWER) { 29 | value = HTTP_HDR_TO_LOWER[key]; 30 | HTTP_HDR_TO_LOWER[value] = value; 31 | } 32 | } 33 | 34 | HTTP_HDR_TO_LOWER['Set-Cookie'] = '\u0001'; 35 | HTTP_HDR_TO_LOWER['set-Cookie'] = '\u0001'; 36 | HTTP_HDR_TO_LOWER['Cookie'] = '\u0002cookie'; 37 | HTTP_HDR_TO_LOWER['cookie'] = '\u0002cookie'; 38 | 39 | const HTTP_HDR_TO_LOWER_0 = { 40 | 'Transfer-Encoding': 'transfer-encoding', 41 | 'Date': 'date', 42 | 'Connection': 'connection', 43 | 'Cache-Control': 'cache-control', 44 | 'Vary': 'vary', 45 | 'Content-Encoding': 'content-encoding', 46 | 'Origin': 'origin', 47 | 'Upgrade': 'upgrade', 48 | 'Expect': 'expect', 49 | 'If-Match': 'if-match', 50 | 'If-None-Match': 'if-none-match', 51 | 'Accept': 'accept', 52 | 'Accept-Encoding': 'accept-encoding', 53 | 'Accept-Language': 'accept-language', 54 | 'X-Forwarded-For': 'x-forwarded-for', 55 | 'X-Forwarded-Host': 'x-forwarded-host', 56 | 'X-Forwarded-Proto': 'x-forwarded-proto' 57 | }; 58 | 59 | { 60 | let key, value, data; 61 | for (key in HTTP_HDR_TO_LOWER_0) { 62 | value = HTTP_HDR_TO_LOWER_0[key]; 63 | data = '\u0000' + value; 64 | HTTP_HDR_TO_LOWER[key] = data; 65 | HTTP_HDR_TO_LOWER[value] = data; 66 | } 67 | } 68 | 69 | const httpHdrToLowerMap = new Map(); 70 | 71 | { 72 | let key, value; 73 | for (key in HTTP_HDR_TO_LOWER) { 74 | value = HTTP_HDR_TO_LOWER[key]; 75 | httpHdrToLowerMap.set(key, value); 76 | } 77 | } 78 | 79 | function matchKnownFields3(field) { 80 | let toLower; 81 | toLower = httpHdrToLowerMap.get(field); 82 | if (toLower) return toLower; 83 | field = field.toLowerCase(); 84 | toLower = httpHdrToLowerMap.get(field); 85 | if (toLower) return toLower; 86 | return '\u0000' + field; 87 | } 88 | 89 | function testMatchKnownFields3() { 90 | return [ 91 | matchKnownFields3('Authorization'), 92 | matchKnownFields3('if-unmodified-since'), 93 | matchKnownFields3('Content-Type'), 94 | matchKnownFields3('last-modified'), 95 | matchKnownFields3('X-Forwarded-For'), 96 | matchKnownFields3('accept'), 97 | matchKnownFields3('Cache-Control'), 98 | matchKnownFields3('cookie') 99 | ]; 100 | } 101 | 102 | benchmark.do(10000000, [testMatchKnownFields3]); 103 | -------------------------------------------------------------------------------- /JavaScript/NodeOptimization/matchKnownFields1.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const benchmark = require('../2-benchmark.js'); 4 | 5 | function matchKnownFields1(field) { 6 | let low = false; 7 | while (true) { 8 | switch (field) { 9 | case 'Content-Type': 10 | case 'content-type': 11 | return 'content-type'; 12 | case 'Content-Length': 13 | case 'content-length': 14 | return 'content-length'; 15 | case 'User-Agent': 16 | case 'user-agent': 17 | return 'user-agent'; 18 | case 'Referer': 19 | case 'referer': 20 | return 'referer'; 21 | case 'Host': 22 | case 'host': 23 | return 'host'; 24 | case 'Authorization': 25 | case 'authorization': 26 | return 'authorization'; 27 | case 'Proxy-Authorization': 28 | case 'proxy-authorization': 29 | return 'proxy-authorization'; 30 | case 'If-Modified-Since': 31 | case 'if-modified-since': 32 | return 'if-modified-since'; 33 | case 'If-Unmodified-Since': 34 | case 'if-unmodified-since': 35 | return 'if-unmodified-since'; 36 | case 'From': 37 | case 'from': 38 | return 'from'; 39 | case 'Location': 40 | case 'location': 41 | return 'location'; 42 | case 'Max-Forwards': 43 | case 'max-forwards': 44 | return 'max-forwards'; 45 | case 'Retry-After': 46 | case 'retry-after': 47 | return 'retry-after'; 48 | case 'ETag': 49 | case 'etag': 50 | return 'etag'; 51 | case 'Last-Modified': 52 | case 'last-modified': 53 | return 'last-modified'; 54 | case 'Server': 55 | case 'server': 56 | return 'server'; 57 | case 'Age': 58 | case 'age': 59 | return 'age'; 60 | case 'Expires': 61 | case 'expires': 62 | return 'expires'; 63 | case 'Set-Cookie': 64 | case 'set-cookie': 65 | return '\u0001'; 66 | case 'Cookie': 67 | case 'cookie': 68 | return '\u0002cookie'; 69 | // The fields below are not used in _addHeaderLine(), but they are common 70 | // headers where we can avoid toLowerCase() if the mixed or lower case 71 | // versions match the first time through. 72 | case 'Transfer-Encoding': 73 | case 'transfer-encoding': 74 | return '\u0000transfer-encoding'; 75 | case 'Date': 76 | case 'date': 77 | return '\u0000date'; 78 | case 'Connection': 79 | case 'connection': 80 | return '\u0000connection'; 81 | case 'Cache-Control': 82 | case 'cache-control': 83 | return '\u0000cache-control'; 84 | case 'Vary': 85 | case 'vary': 86 | return '\u0000vary'; 87 | case 'Content-Encoding': 88 | case 'content-encoding': 89 | return '\u0000content-encoding'; 90 | case 'Origin': 91 | case 'origin': 92 | return '\u0000origin'; 93 | case 'Upgrade': 94 | case 'upgrade': 95 | return '\u0000upgrade'; 96 | case 'Expect': 97 | case 'expect': 98 | return '\u0000expect'; 99 | case 'If-Match': 100 | case 'if-match': 101 | return '\u0000if-match'; 102 | case 'If-None-Match': 103 | case 'if-none-match': 104 | return '\u0000if-none-match'; 105 | case 'Accept': 106 | case 'accept': 107 | return '\u0000accept'; 108 | case 'Accept-Encoding': 109 | case 'accept-encoding': 110 | return '\u0000accept-encoding'; 111 | case 'Accept-Language': 112 | case 'accept-language': 113 | return '\u0000accept-language'; 114 | case 'X-Forwarded-For': 115 | case 'x-forwarded-for': 116 | return '\u0000x-forwarded-for'; 117 | case 'X-Forwarded-Host': 118 | case 'x-forwarded-host': 119 | return '\u0000x-forwarded-host'; 120 | case 'X-Forwarded-Proto': 121 | case 'x-forwarded-proto': 122 | return '\u0000x-forwarded-proto'; 123 | default: 124 | if (low) 125 | return '\u0000' + field; 126 | field = field.toLowerCase(); 127 | low = true; 128 | } 129 | } 130 | } 131 | 132 | // ----- tests ----- 133 | 134 | function testMatchKnownFields1() { 135 | return [ 136 | matchKnownFields1('Authorization'), 137 | matchKnownFields1('if-unmodified-since'), 138 | matchKnownFields1('Content-Type'), 139 | matchKnownFields1('last-modified'), 140 | matchKnownFields1('X-Forwarded-For'), 141 | matchKnownFields1('accept'), 142 | matchKnownFields1('Cache-Control'), 143 | matchKnownFields1('cookie') 144 | ]; 145 | } 146 | 147 | benchmark.do(10000000, [testMatchKnownFields1]); 148 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true, 5 | "node": true 6 | }, 7 | "extends": "eslint:recommended", 8 | "parserOptions": { 9 | "ecmaVersion": "latest" 10 | }, 11 | "globals": { 12 | "BigInt": true, 13 | "api": true 14 | }, 15 | "rules": { 16 | "indent": [ 17 | "error", 18 | 2 19 | ], 20 | "linebreak-style": [ 21 | "error", 22 | "unix" 23 | ], 24 | "quotes": [ 25 | "error", 26 | "single" 27 | ], 28 | "semi": [ 29 | "error", 30 | "always" 31 | ], 32 | "no-loop-func": [ 33 | "error" 34 | ], 35 | "block-spacing": [ 36 | "error", 37 | "always" 38 | ], 39 | "camelcase": [ 40 | "error" 41 | ], 42 | "eqeqeq": [ 43 | "error", 44 | "always" 45 | ], 46 | "strict": [ 47 | "error", 48 | "global" 49 | ], 50 | "brace-style": [ 51 | "error", 52 | "1tbs", 53 | { 54 | "allowSingleLine": true 55 | } 56 | ], 57 | "comma-style": [ 58 | "error", 59 | "last" 60 | ], 61 | "comma-spacing": [ 62 | "error", 63 | { 64 | "before": false, 65 | "after": true 66 | } 67 | ], 68 | "eol-last": [ 69 | "error" 70 | ], 71 | "func-call-spacing": [ 72 | "error", 73 | "never" 74 | ], 75 | "key-spacing": [ 76 | "error", 77 | { 78 | "beforeColon": false, 79 | "afterColon": true, 80 | "mode": "minimum" 81 | } 82 | ], 83 | "keyword-spacing": [ 84 | "error", 85 | { 86 | "before": true, 87 | "after": true, 88 | "overrides": { 89 | "function": { 90 | "after": false 91 | } 92 | } 93 | } 94 | ], 95 | "max-len": [ 96 | "error", 97 | { 98 | "code": 80, 99 | "ignoreUrls": true 100 | } 101 | ], 102 | "max-nested-callbacks": [ 103 | "error", 104 | { 105 | "max": 7 106 | } 107 | ], 108 | "new-cap": [ 109 | "error", 110 | { 111 | "newIsCap": true, 112 | "capIsNew": false, 113 | "properties": true 114 | } 115 | ], 116 | "new-parens": [ 117 | "error" 118 | ], 119 | "no-lonely-if": [ 120 | "error" 121 | ], 122 | "no-trailing-spaces": [ 123 | "error" 124 | ], 125 | "no-unneeded-ternary": [ 126 | "error" 127 | ], 128 | "no-whitespace-before-property": [ 129 | "error" 130 | ], 131 | "object-curly-spacing": [ 132 | "error", 133 | "always" 134 | ], 135 | "operator-assignment": [ 136 | "error", 137 | "always" 138 | ], 139 | "operator-linebreak": [ 140 | "error", 141 | "after" 142 | ], 143 | "semi-spacing": [ 144 | "error", 145 | { 146 | "before": false, 147 | "after": true 148 | } 149 | ], 150 | "space-before-blocks": [ 151 | "error", 152 | "always" 153 | ], 154 | "space-before-function-paren": [ 155 | "error", 156 | { 157 | "anonymous": "never", 158 | "named": "never", 159 | "asyncArrow": "always" 160 | } 161 | ], 162 | "space-in-parens": [ 163 | "error", 164 | "never" 165 | ], 166 | "space-infix-ops": [ 167 | "error" 168 | ], 169 | "space-unary-ops": [ 170 | "error", 171 | { 172 | "words": true, 173 | "nonwords": false, 174 | "overrides": { 175 | "typeof": false 176 | } 177 | } 178 | ], 179 | "no-unreachable": [ 180 | "error" 181 | ], 182 | "no-global-assign": [ 183 | "error" 184 | ], 185 | "no-self-compare": [ 186 | "error" 187 | ], 188 | "no-unmodified-loop-condition": [ 189 | "error" 190 | ], 191 | "no-constant-condition": [ 192 | "error", 193 | { 194 | "checkLoops": false 195 | } 196 | ], 197 | "no-console": [ 198 | "off" 199 | ], 200 | "no-useless-concat": [ 201 | "error" 202 | ], 203 | "no-useless-escape": [ 204 | "error" 205 | ], 206 | "no-shadow-restricted-names": [ 207 | "error" 208 | ], 209 | "no-use-before-define": [ 210 | "error", 211 | { 212 | "functions": false 213 | } 214 | ], 215 | "arrow-parens": [ 216 | "error", 217 | "always" 218 | ], 219 | "arrow-body-style": [ 220 | "error", 221 | "as-needed" 222 | ], 223 | "arrow-spacing": [ 224 | "error" 225 | ], 226 | "no-confusing-arrow": [ 227 | "error", 228 | { 229 | "allowParens": true 230 | } 231 | ], 232 | "no-useless-computed-key": [ 233 | "error" 234 | ], 235 | "no-useless-rename": [ 236 | "error" 237 | ], 238 | "no-var": [ 239 | "error" 240 | ], 241 | "object-shorthand": [ 242 | "error", 243 | "always" 244 | ], 245 | "prefer-arrow-callback": [ 246 | "error" 247 | ], 248 | "prefer-const": [ 249 | "error" 250 | ], 251 | "prefer-numeric-literals": [ 252 | "error" 253 | ], 254 | "prefer-rest-params": [ 255 | "error" 256 | ], 257 | "prefer-spread": [ 258 | "error" 259 | ], 260 | "rest-spread-spacing": [ 261 | "error", 262 | "never" 263 | ], 264 | "template-curly-spacing": [ 265 | "error", 266 | "never" 267 | ], 268 | "consistent-return": [ 269 | "error", 270 | { "treatUndefinedAsUnspecified": true } 271 | ] 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /JavaScript/NodeOptimization/matchKnownFields4.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const benchmark = require('../2-benchmark.js'); 4 | 5 | function fieldKnown(field) { 6 | switch (field) { 7 | case 'Content-Type': 8 | case 'content-type': return 'content-type'; 9 | case 'Content-Length': 10 | case 'content-length': return 'content-length'; 11 | case 'User-Agent': 12 | case 'user-agent': return 'user-agent'; 13 | case 'Referer': 14 | case 'referer': return 'referer'; 15 | case 'Host': 16 | case 'host': return 'host'; 17 | case 'Authorization': 18 | case 'authorization': return 'authorization'; 19 | case 'Proxy-Authorization': 20 | case 'proxy-authorization': return 'proxy-authorization'; 21 | case 'If-Modified-Since': 22 | case 'if-modified-since': return 'if-modified-since'; 23 | case 'If-Unmodified-Since': 24 | case 'if-unmodified-since': return 'if-unmodified-since'; 25 | case 'From': 26 | case 'from': return 'from'; 27 | case 'Location': 28 | case 'location': return 'location'; 29 | case 'Max-Forwards': 30 | case 'max-forwards': return 'max-forwards'; 31 | case 'Retry-After': 32 | case 'retry-after': return 'retry-after'; 33 | case 'ETag': 34 | case 'etag': return 'etag'; 35 | case 'Last-Modified': 36 | case 'last-modified': return 'last-modified'; 37 | case 'Server': 38 | case 'server': return 'server'; 39 | case 'Age': 40 | case 'age': return 'age'; 41 | case 'Expires': 42 | case 'expires': return 'expires'; 43 | case 'Set-Cookie': 44 | case 'set-Cookie': return '\u0001'; 45 | case 'Cookie': 46 | case 'cookie': return '\u0002cookie'; 47 | case 'Transfer-Encoding': 48 | case 'transfer-encoding': return '\u0000transfer-encoding'; 49 | case 'Date': 50 | case 'date': return '\u0000date'; 51 | case 'Connection': 52 | case 'connection': return '\u0000connection'; 53 | case 'Cache-Control': 54 | case 'cache-control': return '\u0000cache-control'; 55 | case 'Vary': 56 | case 'vary': return '\u0000vary'; 57 | case 'Content-Encoding': 58 | case 'content-encoding': return '\u0000content-encoding'; 59 | case 'Origin': 60 | case 'origin': return '\u0000origin'; 61 | case 'Upgrade': 62 | case 'upgrade': return '\u0000upgrade'; 63 | case 'Expect': 64 | case 'expect': return '\u0000expect'; 65 | case 'If-Match': 66 | case 'if-match': return '\u0000if-match'; 67 | case 'If-None-Match': 68 | case 'if-none-match': return '\u0000if-none-match'; 69 | case 'Accept': 70 | case 'accept': return '\u0000accept'; 71 | case 'Accept-Encoding': 72 | case 'accept-encoding': return '\u0000accept-encoding'; 73 | case 'Accept-Language': 74 | case 'accept-language': return '\u0000accept-language'; 75 | case 'X-Forwarded-For': 76 | case 'x-forwarded-for': return '\u0000x-forwarded-for'; 77 | case 'X-Forwarded-Host': 78 | case 'x-forwarded-host': return '\u0000x-forwarded-host'; 79 | case 'X-Forwarded-Proto': 80 | case 'x-forwarded-proto': return '\u0000x-forwarded-proto'; 81 | } 82 | return ''; 83 | } 84 | 85 | function lowerKnown(field) { 86 | switch (field) { 87 | case 'content-type': return 'content-type'; 88 | case 'content-length': return 'content-length'; 89 | case 'user-agent': return 'user-agent'; 90 | case 'referer': return 'referer'; 91 | case 'host': return 'host'; 92 | case 'authorization': return 'authorization'; 93 | case 'proxy-authorization': return 'proxy-authorization'; 94 | case 'if-modified-since': return 'if-modified-since'; 95 | case 'if-unmodified-since': return 'if-unmodified-since'; 96 | case 'from': return 'from'; 97 | case 'location': return 'location'; 98 | case 'max-forwards': return 'max-forwards'; 99 | case 'retry-after': return 'retry-after'; 100 | case 'etag': return 'etag'; 101 | case 'last-modified': return 'last-modified'; 102 | case 'server': return 'server'; 103 | case 'age': return 'age'; 104 | case 'expires': return 'expires'; 105 | case 'set-Cookie': return '\u0001'; 106 | case 'cookie': return '\u0002cookie'; 107 | case 'transfer-encoding': return '\u0000transfer-encoding'; 108 | case 'date': return '\u0000date'; 109 | case 'connection': return '\u0000connection'; 110 | case 'cache-control': return '\u0000cache-control'; 111 | case 'vary': return '\u0000vary'; 112 | case 'content-encoding': return '\u0000content-encoding'; 113 | case 'origin': return '\u0000origin'; 114 | case 'upgrade': return '\u0000upgrade'; 115 | case 'expect': return '\u0000expect'; 116 | case 'if-match': return '\u0000if-match'; 117 | case 'if-none-match': return '\u0000if-none-match'; 118 | case 'accept': return '\u0000accept'; 119 | case 'accept-encoding': return '\u0000accept-encoding'; 120 | case 'accept-language': return '\u0000accept-language'; 121 | case 'x-forwarded-for': return '\u0000x-forwarded-for'; 122 | case 'x-forwarded-host': return '\u0000x-forwarded-host'; 123 | case 'x-forwarded-proto': return '\u0000x-forwarded-proto'; 124 | } 125 | return ''; 126 | } 127 | 128 | function matchKnownFields4(field) { 129 | let toLower; 130 | toLower = fieldKnown(field); 131 | if (toLower) return toLower; 132 | field = field.toLowerCase(); 133 | toLower = lowerKnown(field); 134 | if (toLower) return toLower; 135 | return '\u0000' + field; 136 | } 137 | 138 | function testMatchKnownFields4() { 139 | return [ 140 | matchKnownFields4('Authorization'), 141 | matchKnownFields4('if-unmodified-since'), 142 | matchKnownFields4('Content-Type'), 143 | matchKnownFields4('last-modified'), 144 | matchKnownFields4('X-Forwarded-For'), 145 | matchKnownFields4('accept'), 146 | matchKnownFields4('Cache-Control'), 147 | matchKnownFields4('cookie') 148 | ]; 149 | } 150 | 151 | benchmark.do(10000000, [testMatchKnownFields4]); 152 | --------------------------------------------------------------------------------