javascript - 在创建性能关键类时替代 eval
问题描述
我正在使用一个由节点组成的数据结构,这些节点需要向前/向后遍历,并且需要实时进行大量连接/断开连接(在另一个线程上但仍然如此)。
我已经尝试了各种我能想到的方法来促进这一点,并发现就我的数据类型而言,直接构建到我正在操作的节点中的链表是迄今为止性能最好的方式。
作为参考,在 chrome 上:
- 使用数组(somenode1)的幼稚实现:~1000ms
- 链表类而不是数组(未显示):~600ms
- 节点内置链表(未显示):~350ms
- 链表混合(somenode4):~1100ms
- 使用 eval(somenode5) 的链表混合:~350ms
所以基本上,我想使用 mixin 版本,因为它性能好并且看起来比将链表构建到节点类中更好,但是我不想使用 eval。如果您向下滚动并查看带有和不带有 eval 的 mixin 版本,它们本质上是相同的,但性能却大不相同。
我的实际问题:由于 eval 是一个巨大的安全漏洞,有没有办法创建一个性能与 eval 版本一样好的 mixin 类,而无需实际使用 eval?
天真的实现:
class somenode1 {
constructor() {
this.nexts = [];
this.prevs = [];
}
add_next(item) {
this.nexts.push(item);
item.prevs.push(this);
}
rem_next(item) {
this.nexts.splice(this.nexts.indexOf(item), 1);
item.prevs.splice(item.prevs.indexOf(this), 1);
}
get flat() {
let pile = [this];
for (let i = 0; i < pile.length; i++) pile.push(...pile[i].nexts);
return pile;
}
}
链表混合实现:
function mixin_linked_list_node(base, name, name_or = name + "_or") {
return class extends base {
constructor(...args) {
super(...args);
this[name] = undefined;
this[name_or] = undefined;
}
["add_" + name](item) {
if (!this[name]) { this[name] = item; return; }
let current = this[name];
while (current[name_or]) current = current[name_or];
current[name_or] = item;
}
["rem_" + name](item) {
if (this[name] === item) { this[name] = this[name][name_or]; return; }
let current = this[name];
while (current[name_or] !== item) current = current[name_or];
current[name_or] = current[name_or][name_or];
}
[name + "_push_into"](arr) {
let current = this[name];
while (current) { arr.push(current); current = current[name_or]; }
}
};
}
const somenode4 = mixin_linked_list_node(mixin_linked_list_node(class {
add_next(item) {
this.add_raw_next(item);
item.add_raw_prev(this);
}
rem_next(item) {
this.rem_raw_next(item);
item.rem_raw_prev(this);
}
get flat() {
let pile = [this];
for (let i = 0; i < pile.length; i++) pile[i].raw_next_push_into(pile);
return pile;
}
}, "raw_next"), "raw_prev");
相同的链表混合,但使用 eval()
function mixin_linked_list_node_evil(base, name, name_or = name + "_or") {
return eval(`
()=>class extends base {
constructor(...args) {
super(...args);
this.${name} = undefined;
this.${name_or} = undefined;
}
${"add_" + name}(item) {
if (!this.${name}) { this.${name} = item; return; }
let current = this.${name};
while (current.${name_or}) current = current.${name_or};
current.${name_or} = item;
}
${"rem_" + name}(item) {
if (this.${name} === item) { this.${name} = this.${name}.${name_or}; return; }
let current = this.${name};
while (current.${name_or} !== item) current = current.${name_or};
current.${name_or} = current.${name_or}.${name_or};
}
${name + "_push_into"}(arr) {
let current = this.${name};
while (current) { arr.push(current); current = current.${name_or}; }
}
}
`)();
}
const somenode5 = mixin_linked_list_node_evil(mixin_linked_list_node_evil(class {
add_next(item) {
this.add_raw_next(item);
item.add_raw_prev(this);
}
rem_next(item) {
this.rem_raw_next(item);
item.rem_raw_prev(this);
}
get flat() {
let pile = [this];
for (let i = 0; i < pile.length; i++) pile[i].raw_next_push_into(pile);
return pile;
}
}, "raw_next"), "raw_prev");
这是我的性能基准测试函数,它在某种程度上准确地模拟了负载
function test_nodes(nclass) {
let root, flat;
const t = Date.now();
for (let repe = 0; repe < 1; repe++) {
root = new nclass();
let cbranches = [root];
for (let i = 0; i < 13; i++) {
let nbranches = [];
for (let cbranch of cbranches) {
for (let j = 0; j < 3; j++) {
const nbranch = new nclass();
nbranches.push(nbranch);
cbranch.add_next(nbranch);
cbranch.rem_next(nbranch);
cbranch.add_next(nbranch);
}
}
cbranches = nbranches;
}
flat = root.flat;
}
console.log(Date.now() - t, flat.length, root);
}
test_nodes(somenode1);
test_nodes(somenode4);
test_nodes(somenode5);
// other versions I've tried and not relevant removed
解决方案
推荐阅读
- big-o - 即使这个函数有 3 个 for 循环,它是 O(n) 吗?
- mysql - Combining Data in Two Tables SQL
- mysql - SELECT with left join and union
- algorithm - Is there any case in which repeated Bellman-Ford is better than Floyd-Warshall?
- css - Ionic 4 模态背景
- html - HTML 输入数字填充
- javascript - 使用 forEach 循环从元素中获取 id
- javascript - 在反应中使用拼接添加到数组的正确方法是什么
- python - 如何使用 skimage 中的“imread”来读写?
- node.js - node.js 中的意外标识符