非常感谢@mbrodala的报告,非常感谢那些代码笔!
@mbodala感谢您的代码笔。
我想知道这里是不是有什么误会。
describe('when parsing a template with tags specified followed by the same template with different tags specified', function() {
it('returns different tokens for the latter parse', function() {
var template = "(foo)[bar]";
var parsedWithParens = Mustache.parse(template, ['(', ')']);
var parsedWithBrackets = Mustache.parse(template, ['[', ']']);
assert.notDeepEqual(parsedWithBrackets, parsedWithParens);
});
});
parse
函数仅使用template
作为缓存键进行缓存,因此下次使用parse
解析该模板时,它将返回完全相同的标记,甚至如果指定的tags
不同。
tags
是一个可选参数,当它被省略时,它会回退到mustache.tags
,默认['{{', '}}']
。 回退mustache.tags
用作缓存键的一部分。
我想我知道关于错误修复和期望的情况,我将尝试通过它,我将使用 codepen 作为示例。
Mustache.parse(template, ['[[', ']]']);
在 2.3.0 中,这指示 Mustache 解析template
,使用['[[', ']]']
作为标签。 Mustache 这样做并返回正确的结果,但仅使用template
缓存调用。 请参阅[email protected]
的第 447-450 行:
if (tokens == null)
tokens = cache[template] = parseTemplate(template, tags);
codepen 中的下一个调用是:
var output = Mustache.render(
template,
...
render
不接受tags
参数,因此不将 1 传递给parse
,因此当render
被调用时, parse
使用mustache.tags
作为它的标签。 因此,当调用render
时,它实际上是在告诉parse
,“请解析template
并隐式使用['{{', '}}']
作为tags
。” parse
实际上做了错误的事情,并且完全忽略了tags
和mustache.tags
进行缓存查找。 它碰巧返回了用[['[', ']']]
解析的模板的结果,但这仅仅是因为在整个程序中为template
对parse
的第一次调用是用['[[', ']']]
进行的tags
。
Mustache.parse(template, ['[[', ']]']);
解析结果使用template
和tags
进行缓存,即['[[', ']]']
作为 cacheKey。
下一个电话:
var output = Mustache.render(
template,
...
render
调用parse
,传递template
但省略tags
。 因此parse
有tags
回退到mustache.tags
,这仍然是默认的['{{', '}}']
。 parse
对template
和['{{', '}}']
的缓存键进行缓存查找,并导致缓存未命中,正如预期的那样,因为尚未调用parse
使用template
和标签的组合。 因此,它使用['{{', '}}']
解析template
#$ 。
我相信 v2.3.1 表现出正确的行为。 如果我们要稍微更改https://codepen.io/mbodala/pen/QBJoOx中的 codepen 并针对 v2.3.0 运行它:
var template = "[[item.title]] [[item.value]]";
Mustache.parse(template, ['[[', ']]']);
var output = Mustache.render(
template,
{
item: {
title: "TEST",
value: 1
}
}
);
alert(output);
输出是[[item.title]] [[item.value]]
,这不是预期的。
我可以看到https://codepen.io/mbodala/pen/NBEJjX中的行为可能令人惊讶,因为Mustache.parse
和Mustache.render
调用彼此相邻,而一个可能不会甚至意识到Mustache.parse
甚至需要tags
参数。 (为什么Mustache.parse
甚至需要一个tags
参数?它从未在mustache.js
的任何地方使用过—— parse
只是在内部默认为mustache.tags
。 ..)
如果行为的改变确实违背了错误修复版本的期望,那么我不确定该怎么做。 一种可能性是发布另一个修复了 #664 的错误修复版本,这实际上删除了所有缓存行为(假设在 #643 中,所有缓存查找都将丢失)。 然后我们可以将#664 放回下一个主要版本。 另一种可能性是在错误修复版本中删除所有缓存(而不是发布具有非功能缓存的mustache.js
),然后将所有缓存放回下一个主要修订版中。 前一个选项可能风险较小(代码更改量最少),但后一个选项可能更“正确”。 @phillipj 的想法?
非常感谢从我的 POV 中完全理解的详细研究。
我根本不介意更改,但考虑到不可能将tags
传递给Mustache.render()
以确保缓存命中并且Mustache.parse()
被宣传为缓存template
(这里没有提到tags
)我想知道这是否真的应该恢复。
如果我们假设使用一组自定义的tags
调用Mustache.parse
,我们还可以假设template
使用这些分隔符(顺便说一句,“标签”与“分隔符”应该是也清理了)。 之后,我们可以假设对Mustache.render
的调用预计会起作用,无论给定的template
是如何以及是否已经被缓存,以及如果是这种情况,它是如何编译的。 现在,如果使用自定义tags
,则不能保证这一点。
@mbodala是的,这是有道理的,尽管Mustache.parse(template, ['[[', ']]']);
后跟Mustache.parse(template, ['((', '))']);
给出完全相同的结果仍然是出乎意料的。
这是一个稻草人解决方案/妥协(“稻草人”,因为我不喜欢它,但值得集思广益)。 我们可以单独针对template
和带有标签的template
parse
$。 当parse
被指定tags
调用时,它会针对template
和tags
进行查找。 当我们调用render
时,它调用parse
而没有tags
,然后我们只针对template
进行查找。 想法?
听起来不错,基本上是,但会在保持修复完好无损的同时解决这个问题。 从我的 POV 可以。
@mbodala是您不能将tags
传递给render
的核心问题? 我们也可以在 $ render
中添加一个tags
参数。
@petrkoutnysw这大致是您遇到的问题吗?
这至少是parse()
和render()
之间的不一致。 如果我们确实可以将自定义标签传递给render()
,我们甚至不会使用parse()
。 现在有了适当的缓存,这变得更加明显。
+1 用于向 render() 添加 tags 参数以消除很多混乱——我们也被这个变化所吸引,链接 b/w 解析和渲染总是看起来比必要的更神奇。
好的,那么我们如何在错误修复版本中禁用缓存,以修复当前问题并遵守语义版本控制,并在下一个主要版本的render
方法中重新引入它和tags
? (同样,我不是我提出的稻草人解决方案的忠实粉丝。)
非常感谢@raymond-lam 的彻底演练!
我倾向于建议的错误修复版本,主要是因为 semver 问题和项目的这种行为变化是出乎意料的,因此可能会对野外项目造成严重破坏。
在计划的下一个主要版本中再次重新引入缓存行为,我们可以在发行说明中包含迁移说明。
@phillipj我已经发布了拉取请求#670,它回滚了#643 和#664。 为了降低风险,与其一起禁用缓存,不如简单地回到 v2.3.0 行为(在错误修复版本中)对于 Mustache v2.xx 的依赖者来说似乎是最安全的,我将发出另一个拉取请求以在主要版本中重新引入。
@phillipj #671 重新引入缓存修复,等待主要版本。
创建问题 #672 以解决将tags
添加到 `render.
非常感谢您调查和解决这个问题,你们摇滚。 👍
向@raymond-lam 致敬! 还要感谢您,这对我们了解野外何时发生意外变化至关重要。
v2.3.2已经发布🚀