Chrome 分配配置文件:为什么 handleEvent 的内存消耗如此之大?

Chrome allocations profile: why memory consumption for handleEvent is so huge?

首先,可以查看 medium.com 上的 this post,了解将 pojo 分配为事件侦听器的能力。问题是这个对象应该有 handleEvent 方法,以便能够对某个事件做出反应。 例如:

const handler = {handleEvent(e) {this[`on${e.type}`](e)}};

在上面提到的 post 中 medium.com 作者将我们发送到 benchmark,它的创建正是为了证明 handleEvent 的使用基本上占用 O(1) 内存开销。 例如(不是实际基准):

const handlersQueue = [];

const masterHandler = {
    handleEvent(e) {
        this[`on${e.type}`](e)
    },
    onclick: function() {++this.counter},
    counter: 0
};

for (let i = 0; i < 1e4; i++) {
    const newHandler = Object.create(masterHandler);
    document.body.addEventListener('click', newHandler);
    handlersQueue.push(newHandler);
}

document.body.dispatchEvent(new Event('click'));

在这种情况下,假设所有事件处理程序都将从原型 (masterHandler) 中借用 handleEvent 方法是合乎逻辑的。 作者创建了上述示例的更复杂形式(查看 DynamicHandler class),但总体思路保持不变。 相反,分配配置文件显示 handleEvent 函数(Chrome 版本 64.0.3282.186(官方构建)(64 -bit), MacOS High Sierra): 问题是:

这里是 V8 开发人员。字符串连接,即原始基准中的 'on' + e.type,或基于模板文字的替代方案:

`on${e.type}`

导致(毫不奇怪?)在每次调用时创建一个字符串。 100,000 次调用的 3.3MB 是每次迭代 33 字节;字符串 "onclick" 在堆上需要 32 个字节,所以这解释了大部分内容。

虽然这不是特别 有效,但这些字符串至少是 short-lived,即垃圾收集器将快速清除它们。除非您采用分配配置文件,否则您可能甚至不会注意到;另一方面,如果您最终要解决真正的内存消耗问题,那么出于这个原因,消除配置文件中的此类噪音可能是值得的。

如果你想节省开销,你可以简单地将 "onclick" 函数重命名为 "click" (对于任何其他事件都类似),这样你就不需要在全部.