while (c) {
tag`str0 ${e} str1`
}
JavaScript 运行时创建一个卡住数组,如 Object.freeze(['str0 ', 'str1'])
但有一个额外的 .raw
属性。
是否可以将该对象用作 WeakMap
中的键以避免每次循环都基于数组重做工作?
const memoTable = new WeakMap
function tag(templateStrings, ...values) {
let cached = memoTable.get(templateStrings)
if (!cached) {
// Compute cached and put it in the table for next time.
}
// Do something with cached and values
}
第12.2.9.3 Runtime Semantics: GetTemplateObject ( templateLiteral )描述了这个值是如何被缓存的:
- Let realm be the current Realm Record.
- Let templateRegistry be realm.[[TemplateMap]].
因此在上面的循环中使用 tag
应该是相同的,这对于 key 来说是一个很好的属性。
在我看来,[[TemplateMap]] 必须弱引用模板对象数组,否则
for (let i = 0; i < 1e6; ++i) {
eval('(() => {})`' + i + '`');
}
会泄漏内存。
我在规范中没有看到任何内容,但对于广泛使用的 JavaScript 引擎来说,是否最终会收集未在可重新输入范围内使用的标记字符串模板的 WeakMap 条目?
我问是因为我已经实现了 something基于这个假设,但还没有想出如何测试它。
最佳答案
Is it okay to use that object as a key in a WeakMap to avoid having to redo work based on the array each time through the loop?
是的,这正是您想要做的,而且它是模板字面量的重要特性之一。
It seems to me that the [[TemplateMap]] would have to weakly reference the template object array because otherwise
for (let i = 0; i < 1e6; ++i) { eval('(() => {})`' + i + '`'); }
would leak memory.
它确实泄漏了,因为 [[TemplateMap]]
并不弱。 :(
这是对当前规范的公开讨论点。撰写本文时的讨论是,是否应更改规范以使模板文字成为每个源文本位置,而不是让 [[TemplateMap]]
成为全局状态。例如在撰写本文时:
var id = v => v;
id`tpl` === id`tpl` // true
这有点奇怪。
创建两个单独的模板是否可以接受?如果是这样,那么至少有可能允许您的 eval
示例收集模板。
你可以在这里看到一些讨论,https://github.com/tc39/ecma262/issues/840 ,至少可以暂时解决这个问题。
编辑:
规范确实发生了变化,因此模板现在是按源位置而不是按领域的,因此具有相同内容和不同位置的两个模板将是两个不同的对象。这意味着如果引擎的源文件不再可访问,引擎可能会对模板文字对象进行垃圾回收。
关于javascript - 标记的模板文字的 TemplateObject 数组是否被其领域弱引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48528281/