【发布时间】:2018-08-13 19:07:01
【问题描述】:
我正在使用带有陷阱的Proxy 对象来跟踪对象键,以便我可以轻松地迭代和/或从对象中选择一个随机键,而性能开销很小。目前,我在添加键时将它们存储在一个数组中。这对于插入和随机选择非常有效,但是当一个属性被删除时,开销是巨大的:
// Benchmark
var testObject = createProxy();
var start = performance.now();
for( var i = 0; i < 1e4; i++ )
testObject[Math.random() * 1e6 << 0] = true;
for( var i in testObject )
if( i[0] !== '_' )
delete testObject[ i ];
var end = performance.now();
var total = ( end - start );
console.log( 'Test took ' + total + ' ms' );
// Implementation
function createProxy() {
function keyTracker() {
const set = new Set();
function defineProperty( target, property, descriptor ) {
target[property] = descriptor.value;
if( property[0] === '_' ) return true;
if( set.has( property ) ) return true;
set.add( property );
target[ '__keys' ].push( property );
return true;
}
function deleteProperty( target, property ) {
if( property[ 0 ] === '_' ) return true;
delete target[ property ];
if( !set.delete( property ) ) return true;
target[ '__keys' ] = target[ '__keys' ].filter(
key => key !== property
);
return true;
}
return { defineProperty, deleteProperty };
}
var proxy = new Proxy(
Object.defineProperty( {}, '__keys', {
configurable: true,
enumerable: false,
writable: true,
value: []
} ), keyTracker() );
return proxy;
}
随着对象中键数量的增长,调用Array.filter() 的开销会成倍增加。我正在寻找一种能够让我避免调用它来删除单个元素的解决方案。
有没有一种方法可以重新构建它以允许 O(1) 插入、随机选择和删除键?
【问题讨论】:
-
你需要关心这个......为什么?用户不会注意到它是每秒 1000 万次操作还是 100 万次......如果你真的,真的,真的需要你不应该使用的那么多性能Proxy(slow)... 或 Object.defineProperty(slow)... 或 JavaScript。
-
我了解 Proxy/defineProperty 等的性能开销。开销不是问题。问题是当对象中的键数量(用作字典)增长太大时,性能会呈指数下降,因为它当前依赖于数组,并且从 10k 键增加到 100 万键是不可行的。这将在 NodeJS v10 中运行,而不是在浏览器中运行,而这个选择不在我的掌控之中。