4
while (c) {
  tag`str0 ${e} str1`
}

JavaScript 运行时创建一个冻结数组,Object.freeze(['str0 ', ' str1'])但具有附加.raw属性。

是否可以将该对象用作 a 中的键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 节运行时语义:GetTemplateObject ( templateLiteral )描述了如何缓存此值:

  1. 领域成为当前领域记录。
  2. templateRegistry领域.[[TemplateMap]]。

所以tag在上面的循环中从使用到使用应该是相同的,这对于键来说是一个很好的属性。

在我看来, [[TemplateMap]] 将不得不弱引用模板对象数组,否则

for (let i = 0; i < 1e6; ++i) {
  eval('(() => {})`' + i + '`');
}

会泄漏内存。

我在规范中没有看到任何内容,但是对于广泛使用的 JavaScript 引擎,是否最终会收集用于标记字符串模板的 WeakMap 条目不在可重新输入的范围内?

我问是因为我已经根据这个假设实现了一些东西,但还没有弄清楚如何测试它。

4

2 回答 2

6

是否可以将该对象用作 WeakMap 中的键以避免每次通过循环时都必须基于数组重做工作?

是的,这正是你要做的,它是模板文字的一大特色。

在我看来, [[TemplateMap]] 将不得不弱引用模板对象数组,否则

for (let i = 0; i < 1e6; ++i) {
  eval('(() => {})`' + i + '`');
}

会泄漏内存。

事实上它确实会泄漏,因为[[TemplateMap]]它并不弱。:(

这是关于当前规范的公开讨论点。目前的讨论是是否应该将规范更改为,而不是具有[[TemplateMap]]全局状态,而不是使其成为 per-source-text-position。例如现在

var id = v => v;
id`tpl` === id`tpl` // true

打破这样创建两个单独的模板是否可以接受?如果是这样,那么至少有可能eval允许您的示例收集模板。

你可以在这里看到一些讨论,https://github.com/tc39/ecma262/issues/840,至少暂时可以解决这个问题。

于 2018-01-30T18:46:53.290 回答
1

在我看来, [[TemplateMap]] 将不得不弱引用模板对象数组

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

可以将该对象用作 WeakMap 中的键以避免重做工作吗?

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

于 2018-01-30T18:51:32.633 回答