Last active
December 21, 2021 04:39
-
-
Save thysultan/15f645ddcdb5540d0bca2cba5cafd1e4 to your computer and use it in GitHub Desktop.
vdom creation #jsbench #jsperf (https://jsbench.github.io/#15f645ddcdb5540d0bca2cba5cafd1e4) #jsbench #jsperf
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"/> | |
<title>vdom creation #jsbench #jsperf</title> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/benchmark/1.0.0/benchmark.min.js"></script> | |
<script src="./suite.js"></script> | |
</head> | |
<body> | |
<h1>Open the console to view the results</h1> | |
<h2><code>cmd + alt + j</code> or <code>ctrl + alt + j</code></h2> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
(function (factory) { | |
if (typeof Benchmark !== "undefined") { | |
factory(Benchmark); | |
} else { | |
factory(require("benchmark")); | |
} | |
})(function (Benchmark) { | |
var suite = new Benchmark.Suite; | |
Benchmark.prototype.setup = function () { | |
'use strict'; | |
var obj = Object; | |
var arr = Array; | |
var nop = function(){}; | |
function a (type, value,a,b,c,d,e,f) {'use strict'; | |
var index = 0 | |
var length = a !== undefined ? 3 : 2 | |
var of = value === null || value instanceof obj | |
var position = of ? 2 : 1 | |
var size = length - position | |
var identity = 0 | |
var props = of ? value : {} | |
var children = new arr(size) | |
if (size > 0) { | |
if (a !== undefined) {children[0] = a;if (b !== undefined) {children[1] = b;if (c !== undefined) {children[2] = c;} | |
if (d !== undefined) {children[2] = d;if (e !== undefined) {children[2] = e;if (f !== undefined) {children[2] = f; | |
if (arguments.length > 8) { | |
while (position < length) { | |
children[8+index++] = arguments[8+position++] | |
} | |
} | |
}}}}} | |
} | |
switch (typeof type) { | |
case 'object': identity = 1; children[index] = null | |
break | |
case 'function': identity = 2; if (size > 0) props.children = size > 1 ? children : children[0] | |
} | |
return {id: identity, type: type, props: props, children: children, own: null} | |
} | |
// ------------------ | |
function b (type, props, child) {'use strict'; | |
var index = 0 | |
// var length = arguments.length | |
// var of = props === null || props instanceof obj | |
// var position = of ? 2 : 1 | |
// var size = length - position | |
var identity = 0 | |
var properties = props//of ? props : {} | |
var children = child | |
// if (size > 0) { | |
// for (; position < length; ++position) { | |
// children[index++] = arguments[position] | |
// } | |
// } | |
var size=arguments.length | |
if (size > 2) { | |
if (size > 3) { | |
children = slice.call(arguments, 2) | |
} | |
} | |
switch (typeof type) { | |
case 'object': | |
identity = 1, children[index] = null | |
break | |
case 'function': | |
identity = 2 | |
// if (size > 0) { | |
// properties.children = size > 1 ? children : children[0] | |
// } | |
} | |
return {id: identity, type: type, props: props, children: children, own: null} | |
// return new struct(identity, type, properties, children) | |
// return element.type = type, element | |
} | |
function c (type, value,a,b,c,d,e,f) {'use strict'; | |
var index = 0 | |
var length = a !== undefined ? 3 : 2 | |
var of = value === null || value instanceof obj | |
var position = of ? 2 : 1 | |
var size = length - position | |
var identity = 0 | |
var props = of ? value : {} | |
var children = new arr(size) | |
if (size > 0) { | |
if (a !== undefined) {children[0] = a;if (b !== undefined) {children[1] = b;if (c !== undefined) {children[2] = c;} | |
if (d !== undefined) {children[2] = d;if (e !== undefined) {children[2] = e;if (f !== undefined) {children[2] = f; | |
if (arguments.length > 8) { | |
while (position < length) { | |
children[8+index++] = arguments[8+position++] | |
} | |
} | |
}}}}} | |
} | |
switch (typeof type) { | |
case 'object': identity = 1; children[index] = null | |
break | |
case 'function': identity = 2; if (size > 0) props.children = size > 1 ? children : children[0] | |
} | |
return new Struct(identity, type, props, children) | |
} | |
function d (type, value,a,b,c,d,e,f) {'use strict'; | |
var index = 0 | |
var length = a !== undefined ? 3 : 2 | |
var of = props === null || props instanceof obj | |
var position = of ? 2 : 1 | |
var size = length - position | |
var identity = 0 | |
var props = of ? value : {} | |
var children = new arr(size) | |
if (size > 0) { | |
if (a !== undefined) {children[0] = a;if (b !== undefined) {children[1] = b;if (c !== undefined) {children[2] = c;} | |
if (d !== undefined) {children[2] = d;if (e !== undefined) {children[2] = e;if (f !== undefined) {children[2] = f; | |
if (arguments.length > 8) { | |
while (position < length) { | |
children[8+index++] = arguments[8+position++] | |
} | |
} | |
}}}}} | |
} | |
switch (typeof type) { | |
case 'object': identity = 1; children[index] = null | |
break | |
case 'function': identity = 2; if (size > 0) props.children = size > 1 ? children : children[0] | |
} | |
return new struct(identity, type, props, children) | |
} | |
function e (type, value,a) {'use strict'; | |
var index = 0 | |
var length = a !== undefined ? 3 : 2 | |
// var of = value === null || value instanceof obj | |
// var position = of ? 2 : 1 | |
var size = length// - position | |
var identity = 0 | |
var props = value | |
var children | |
if (size == 3) { | |
if (a !== undefined) { | |
children=a; | |
} | |
} | |
switch (typeof type) { | |
case 'object': identity = 1; //children[index] = null | |
break | |
case 'function': identity = 2; if (size > 0) props.children = children | |
} | |
return {id: identity, type: type, props: props, children: children, own: null} | |
} | |
function struct (id, type, props, children) {'use strict'; | |
this.id = id | |
this.type = type | |
this.props = props | |
this.children = children | |
this.own = null | |
// this.key = key | |
// this.parent = null | |
// this.context = null | |
// this.owner = null | |
// this.value = null | |
// this.state = null | |
// this.stack = null | |
} | |
struct.prototype={handleEvent:nop} | |
class Struct { | |
constructor(id, type, props, children) {'use strict'; | |
this.id = id | |
this.type = type | |
this.props = props | |
this.children = children | |
this.own = null | |
} | |
handleEvent(){} | |
} | |
// ---------------------- | |
var data = [null,null,null,null,null,null,null] | |
// ------------------------------------------------- | |
function createElement(type, props, children) {'use strict'; | |
let normalizedProps = {}, | |
key, | |
ref, | |
i; | |
for (i in props) { | |
if (i == 'key') key = props[i]; | |
else if (i == 'ref') ref = props[i]; | |
else normalizedProps[i] = props[i]; | |
} | |
if (arguments.length > 2) { | |
normalizedProps.children = | |
arguments.length > 3 ? slice.call(arguments, 2) : children; | |
} | |
// If a Component VNode, check for and apply defaultProps | |
// Note: type may be undefined in development, must never error here. | |
if (typeof type == 'function' && type.defaultProps != null) { | |
for (i in type.defaultProps) { | |
if (normalizedProps[i] === undefined) { | |
normalizedProps[i] = type.defaultProps[i]; | |
} | |
} | |
} | |
return createVNode(type, normalizedProps, key, ref, null); | |
} | |
var options={_catchError:null} | |
var vnodeId=0 | |
var slice = [].slice; | |
function createVNode(type, props, key, ref, original) {'use strict'; | |
// V8 seems to be better at detecting type shapes if the object is allocated from the same call site | |
// Do not inline into createElement and coerceToVNode! | |
const vnode = { | |
type, | |
props, | |
key, | |
ref, | |
_children: null, | |
_parent: null, | |
_depth: 0, | |
_dom: null, | |
// _nextDom must be initialized to undefined b/c it will eventually | |
// be set to dom.nextSibling which can return `null` and it is important | |
// to be able to distinguish between an uninitialized _nextDom and | |
// a _nextDom that has been set to `null` | |
_nextDom: undefined, | |
_component: null, | |
_hydrating: null, | |
constructor: undefined, | |
_original: original == null ? ++vnodeId : original | |
}; | |
// Only invoke the vnode hook if this was *not* a direct copy: | |
if (original == null && options.vnode != null) options.vnode(vnode); | |
return vnode; | |
} | |
const REACT_ELEMENT_TYPE = 0 | |
const hasOwnProperty = obj.prototype.hasOwnProperty | |
const RESERVED_PROPS = { | |
key: true, | |
ref: true, | |
__self: true, | |
__source: true, | |
}; | |
const ReactElement = function(type, key, ref, self, source, owner, props) {'use strict'; | |
const element = { | |
// This tag allows us to uniquely identify this as a React Element | |
$$typeof: REACT_ELEMENT_TYPE, | |
// Built-in properties that belong on the element | |
type: type, | |
key: key, | |
ref: ref, | |
props: props, | |
// Record the component responsible for creating this element. | |
_owner: owner, | |
}; | |
return element; | |
}; | |
function jsx(type, config, maybeKey) { | |
let propName; | |
// Reserved names are extracted | |
const props = {}; | |
let key = null; | |
let ref = null; | |
// Currently, key can be spread in as a prop. This causes a potential | |
// issue if key is also explicitly declared (ie. <div {...props} key="Hi" /> | |
// or <div key="Hi" {...props} /> ). We want to deprecate key spread, | |
// but as an intermediary step, we will use jsxDEV for everything except | |
// <div {...props} key="Hi" />, because we aren't currently able to tell if | |
// key is explicitly declared to be undefined or not. | |
if (maybeKey !== undefined) { | |
key = '' + maybeKey; | |
} | |
if (hasValidKey(config)) { | |
key = '' + config.key; | |
} | |
if (hasValidRef(config)) { | |
ref = config.ref; | |
} | |
// Remaining properties are added to a new props object | |
for (propName in config) { | |
if ( | |
hasOwnProperty.call(config, propName) && | |
!RESERVED_PROPS.hasOwnProperty(propName) | |
) { | |
props[propName] = config[propName]; | |
} | |
} | |
// Resolve default props | |
if (type && type.defaultProps) { | |
const defaultProps = type.defaultProps; | |
for (propName in defaultProps) { | |
if (props[propName] === undefined) { | |
props[propName] = defaultProps[propName]; | |
} | |
} | |
} | |
return ReactElement( | |
type, | |
key, | |
ref, | |
undefined, | |
undefined, | |
null, | |
props, | |
); | |
} | |
function hasValidRef(config) {'use strict'; | |
return config.ref !== undefined; | |
} | |
function hasValidKey(config) {'use strict'; | |
return config.key !== undefined; | |
} | |
}; | |
Benchmark.prototype.teardown = function () { | |
data = data.map(v => { | |
if (v === undefined) { | |
throw 'Error' | |
} else { | |
return Math.random() > 0.5 ? null : v | |
} | |
}) | |
}; | |
suite.add("var value = a('type',{a:1},null) // no-arity, arguments access, pojo", function () { | |
var value = a('type',{a:1},null) // no-arity, arguments access, pojo | |
data[0]=value.id | |
// let n = 0; | |
// for (let c of value.children) { | |
// n += typeof c === 'object' ? c?.id : 0; | |
// } | |
// data[0] = n; | |
}); | |
suite.add("var value = b('type',{a:1},null) // strict-arity, arguments access, pojo", function () { | |
var value = b('type',{a:1},null) // strict-arity, arguments access, pojo | |
//data[1]=value.id | |
// let n = 0; | |
// for (let c of value.children) { | |
// n += typeof c === 'object' ? c?.id : 0; | |
// } | |
// data[1] = n; | |
}); | |
suite.add("var value = c('type',{a:1},null) // no-arity, arguments access, prototype class", function () { | |
var value = c('type',{a:1},null) // no-arity, arguments access, prototype class | |
data[2]=value.id | |
// let n = 0; | |
// for (let c of value.children) { | |
// n += typeof c === 'object' ? c.id : 0; | |
// } | |
// data[2] = n; | |
}); | |
suite.add("var value = d('type',{a:1},null) // no-arity, arguments access, native class", function () { | |
var value = d('type',{a:1},null) // no-arity, arguments access, native class | |
data[3]=value.id | |
// let n = 0; | |
// for (let c of value.children) { | |
// n += typeof c === 'object' ? c.id : 0; | |
// } | |
// data[3] = n; | |
}); | |
suite.add("var value = e('type',{a:1},null) // strict-arity, no arguments access, pojo object", function () { | |
var value = e('type',{a:1},null) // strict-arity, no arguments access, pojo object | |
data[4]=value.id | |
// let n = 0; | |
// for (let c of value.children) { | |
// n += typeof c === 'object' ? c.id : 0; | |
// } | |
// data[4] = n; | |
}); | |
suite.add("var value = createElement('type',{a:1},null) // preact", function () { | |
var value = createElement('type',{a:1},null) // preact | |
data[5]=value._depth | |
// let n = 0; | |
// for (let c of value.children) { | |
// n += typeof c === 'object' ? c.id : 0; | |
// } | |
// data[5] = n; | |
}); | |
suite.add("var value = jsx(\"type\", {a: 1,}); // react new _jsx", function () { | |
var value = jsx("type", {a: 1,}); // react new _jsx | |
data[6]=value._owner | |
// let n = 0; | |
// for (let c of value.children) { | |
// n += typeof c === 'object' ? c.id : 0; | |
// } | |
// data[6] = n; | |
}); | |
suite.on("cycle", function (evt) { | |
console.log(" - " + evt.target); | |
}); | |
suite.on("complete", function (evt) { | |
console.log(new Array(30).join("-")); | |
var results = evt.currentTarget.sort(function (a, b) { | |
return b.hz - a.hz; | |
}); | |
results.forEach(function (item) { | |
console.log((idx + 1) + ". " + item); | |
}); | |
}); | |
console.log("vdom creation #jsbench #jsperf"); | |
console.log(new Array(30).join("-")); | |
suite.run(); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment