标记的模板文字的 TemplateObject 数组是否被其领域弱引用?

Are TemplateObject arrays for tagged template literals weakly referenced by their realm?

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 ) 部分描述了如何缓存此值:

  1. Let realm be the current Realm Record.
  2. Let templateRegistry be realm.[[TemplateMap]].

所以在上面的循环中使用 tag 应该是一样的,这将是一个很好的 属性 键。

在我看来 [[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,至少可以暂时解决这个问题。

编辑:

规范确实发生了变化,因此模板现在是按源位置而不是按领域的,因此具有相同内容和不同位置的两个模板将是两个不同的对象。这意味着如果引擎的源文件不再可用,引擎可能会垃圾收集模板文字对象。

It seems to me that the [[TemplateMap]] would have to weakly reference the template object array

我不知道这里的实际实现是什么,但规范确实将领域 [[TemplateMap]] 描述为永远不会被清空。在循环中评估许多不同的模板标签确实会严重泄漏内存,因此 don't do that.

Is it okay to use that object as a key in a WeakMap to avoid having to redo work?

是的,非常好。如果全局 [[TemplateMap]] 确实泄漏内存,这会加剧问题,但如果没有,那么通过使用 weak 映射就不会造成问题。