对于以下函数,我们有针对 {{simple-ident?}}, {{qualified-ident?}}, {{simple-symbol?}}, {{qualified-symbol?}}, {{simple-keyword?}}, 和 {{qualified-keyword?}} 的优化措施。
可以单独进行两次优化。
在 {{boolean}} 被使用的地方(合格函数),我们可以使用 {{some?}} 来实现更快的版本
(boolean (and (symbol? x) (namespace x) true))
可以转换为
(and (symbol? x) (some? (namespace x)))
现在专注于 V8,对于
(simple-benchmark [x 'a/b f #(qualified-symbol? x)] (f) 100000000)
和减去基准成本的
(simple-benchmark [x 'a/b f (fn [] x)] (f) 100000000)
得到速度提升了 1.74。
由于我们知道使用 {{namespace}} 时我们正在处理关键字或符号,因此我们可以进一步使用 {{(.-ns x)}}。
仅此就给出了 2.21 的速度提升,当与之前的优化组合作为
(and (symbol? x) (some? (.-ns x)))
时,我们看到了接近无限的速度提升(该操作实际上变得免费,与基准耗时相同)。
请注意,我们可能可以使用由谓词引发的类型推理以及一个用于 {{namespace}} 的新宏,该宏生成 {{.-ns}},但 CLJS-2866 目前依赖于在 {{if}} 中查看测试,而像上面这样的表达式导致带有短路操作符 {{&&}} 的优化的 {{js*}} 输出。
这些优化之所以好,是因为这些函数在基于规范的生成代码测试中经常使用,其中性能可能是一个问题。
我们在 {{cljs.predicates-test}} 中对这些函数有测试覆盖率。
以下是目前为 {{qualified-symbol?}} 发射的 JavaScript 引用
function cljs$core$qualified_symbol_QMARK_(x) {
return cljs.core.boolean$(
(function() {
var and__8540__auto__ = x instanceof cljs.core.Symbol;
if (and__8540__auto__) {
var and__8540__auto____$1 = cljs.core.namespace(x);
if (cljs.core.truth_(and__8540__auto____$1)) {
return true;
} else {
return and__8540__auto____$1;
}
} else {
return and__8540__auto__;
})()
);
}
以下是修改后的结果
function cljs$user$qualified_symbol_QMARK_(x) {
return x instanceof cljs.core.Symbol && !(x.ns == null);
}
(这个修改后的实现的紧凑性意味着它可能可以通过 Closure 进一步内联以获得更多的速度优化。)