Toggle navigation
MeasureThat.net
Create a benchmark
Tools
Feedback
FAQ
Register
Log In
Eval vs new function with proxy (edit)
(version: 1)
Comparing performance of:
Compile and exec vs Eval vs Exec only
Created:
4 years ago
by:
Registered User
Jump to the latest result
Script Preparation code:
const filters = new Map(); const limiters = new Map(); function filter(name, handler) { if (typeof name !== 'string') { throw new TypeError('First argument must be a string.'); } if (typeof handler !== 'function') { throw new TypeError('Second argument must be a function.'); } if (filters.has(name)) { throw new Error(`A filter named ${name} is already registered.`); } filters.set(name, handler); } function limiter(name, handler) { if (typeof name !== 'string') { throw new TypeError('First argument must be a string.'); } if (typeof handler !== 'function') { throw new TypeError('Second argument must be a function.'); } if (limiters.has(name)) { throw new Error(`A limiter named ${name} is already registered.`); } limiters.set(name, handler); } function compileRawExpression(src) { return new Function('context', 'tempVars', // eslint-disable-line `const sandbox = $nxCompileToSandbox(context, tempVars) try { with (sandbox) { return ${src} } } catch (err) { if (!(err instanceof TypeError)) throw err } $nxClearSandbox()`); } function compileRawCode(src) { return new Function('context', 'tempVars', // eslint-disable-line `const sandbox = $nxCompileToSandbox(context, tempVars) with (sandbox) { ${src} } $nxClearSandbox()`); } const filterRegex = /(?:[^\|]|\|\|)+/g; const limiterRegex = /(?:[^&]|&&)+/g; const argsRegex = /\S+/g; function parseExpression(src) { const tokens = src.match(filterRegex); if (tokens.length === 1) { return compileRawExpression(tokens[0]); } const expression = { exec: compileRawExpression(tokens[0]), filters: [] }; for (let i = 1; i < tokens.length; i++) { let filterTokens = tokens[i].match(argsRegex); const filterName = filterTokens.shift(); const effect = filters.get(filterName); if (!effect) { throw new Error(`There is no filter named: ${filterName}.`); } expression.filters.push({ effect, argExpressions: filterTokens.map(compileRawExpression) }); } return expression; } function parseCode(src) { const tokens = src.match(limiterRegex); if (tokens.length === 1) { return compileRawCode(tokens[0]); } const code = { exec: compileRawCode(tokens[0]), limiters: [] }; for (let i = 1; i < tokens.length; i++) { const limiterTokens = tokens[i].match(argsRegex); const limiterName = limiterTokens.shift(); const effect = limiters.get(limiterName); if (!effect) { throw new Error(`There is no limiter named: ${limiterName}.`); } code.limiters.push({ effect, argExpressions: limiterTokens.map(compileRawExpression) }); } return code; } const expressionCache = new Map(); const codeCache = new Map(); function compileExpression(src) { if (typeof src !== 'string') { throw new TypeError('First argument must be a string.'); } let expression = expressionCache.get(src); if (!expression) { expression = parseExpression(src); expressionCache.set(src, expression); } if (typeof expression === 'function') { return expression; } return function evaluateExpression(context, tempVars) { let value = expression.exec(context, tempVars); for (let filter of expression.filters) { const args = filter.argExpressions.map(evaluateArgExpression, context); value = filter.effect(value, ...args); } return value; }; } function compileCode(src) { if (typeof src !== 'string') { throw new TypeError('First argument must be a string.'); } let code = codeCache.get(src); if (!code) { code = parseCode(src); codeCache.set(src, code); } if (typeof code === 'function') { return code; } const context = {}; return function evaluateCode(state, tempVars) { let i = 0; function next() { Object.assign(context, tempVars); if (i < code.limiters.length) { const limiter = code.limiters[i++]; const args = limiter.argExpressions.map(evaluateArgExpression, state); limiter.effect(next, context, ...args); } else { code.exec(state, tempVars); } } next(); }; } function evaluateArgExpression(argExpression) { return argExpression(this); } const hasHandler = { has }; const allHandlers = { has, get }; const globals = new Set(); let temp; let globalObj; if (typeof window !== 'undefined') globalObj = window; // eslint-disable-line else if (typeof global !== 'undefined') globalObj = global; // eslint-disable-line else if (typeof self !== 'undefined') globalObj = self; // eslint-disable-line globalObj.$nxCompileToSandbox = toSandbox; globalObj.$nxClearSandbox = clearSandbox; function expose(...globalNames) { for (let globalName of globalNames) { globals.add(globalName); } } function hide(...globalNames) { for (let globalName of globalNames) { globals.delete(globalName); } } function hideAll() { globals.clear(); } function has(target, key) { return globals.has(key) ? key in target : true; } function get(target, key) { return key in temp ? temp[key] : target[key]; } function toSandbox(obj, tempVars) { if (tempVars) { temp = tempVars; return new Proxy(obj, allHandlers); } return new Proxy(obj, hasHandler); } function clearSandbox() { temp = undefined; } window.codeopti = compileCode('return prop1 + prop2');
Tests:
Compile and exec
const code = compileCode('return prop1 + prop2'); const sum = code({prop1: 1, prop2: 2});
Eval
eval('1+2');
Exec only
const sum = codeopti({prop1: 1, prop2: 2});
Rendered benchmark preparation results:
Suite status:
<idle, ready to run>
Run tests (3)
Previous results
Fork
Test case name
Result
Compile and exec
Eval
Exec only
Fastest:
N/A
Slowest:
N/A
Latest run results:
No previous run results
This benchmark does not have any results yet. Be the first one
to run it!
Autogenerated LLM Summary
(model
llama3.2:3b
, generated one year ago):
Based on the provided information, I'll attempt to answer your question. **Context** The code snippet appears to be a part of a compiler or interpreter for a JavaScript-like language. The `compileCode` function takes a string as input and returns an object with a `limiters` property. This object is then used to execute a series of operations. **Benchmarking** The benchmarking data shows the execution time for three different test cases: 1. **Eval**: Evaluating the expression `eval('1+2')` 2. **Compile and exec**: Compiling the code `const code = compileCode('return prop1 + prop2');` and then executing it with an object `{prop1: 1, prop2: 2}` 3. **Exec only**: Executing the compiled code without compiling it first **Observations** * The Chrome 96 browser consistently performs the best among the three test cases. * The `Compile and exec` test case is slower than the `Eval` and `Exec only` tests, indicating that compilation introduces some overhead. * The `Compiling` test case has a higher variance in execution times, suggesting that there may be variations in how the code is executed. **Question** Unfortunately, I don't see a specific question being asked. Are you looking for: 1. An explanation of the benchmarking results? 2. Insights on how to optimize the compilation process? 3. Suggestions for improving the performance of the `compileCode` function? Please provide more context or clarify what you're looking for, and I'll do my best to assist you!
Related benchmarks:
eval vs new Function vs regular function
eval() vs new Function()
eval vs new Function without cached parsing
eval vs Function()
eval vs new Function vs vanilla
Comments
Confirm delete:
Do you really want to delete benchmark?