使用闭包编译器简单优化从函数内部删除调试代码
Removing debug code from inside a function using Closure Compiler simple optimisations
我正在寻找一种从函数中删除调试代码的方法,以便我可以将测试钩子添加到闭包中。 我读过Google闭包编译器高级:在编译时删除代码块,并使用以下方法测试删除调试代码:
/** @define {boolean} */
var DEBUG = true;
if (DEBUG) {
console.log('remove me');
}
使用--define='DEBUG=false'
进行简单优化可将其减少到var DEBUG=!1;
。 这同样适用于:
/** @const */
var DEBUG = false;
if (DEBUG) {
console.log('remove me');
}
我遇到麻烦的地方是在函数中使用此约定:
/** @const */
var DEBUG = false;
function logMe() {
if (DEBUG) {
console.log('remove me');
}
}
这简化为以下内容:
var DEBUG=!1;function logMe(){DEBUG&&console.log("remove me")};
我希望它能进一步减少到:
var DEBUG=!1;function logMe(){};
是否有原因无法按预期工作? 我真的只是在寻找一种干净的方法来剥离调试代码,并且还没有准备好投入高级优化。
更新
根据@John的回答,我实现了自己的编译器,并发现以下配置将在@define
的情况下从代码内部和外部删除if (DEBUG) {}
:
CompilerOptions options = new CompilerOptions();
CompilationLevel.SIMPLE_OPTIMIZATIONS.setOptionsForCompilationLevel(options);
//options.setInlineConstantVars(true);
options.setInlineVariables(CompilerOptions.Reach.ALL);
options.setDefineToBooleanLiteral("DEBUG", false);
这对于具有以下限制的单个文件来说足够有效:
- 这需要在每个文件中定义
var DEBUG
,这是不好的做法。 - 合并多个文件时,只能有一个
var DEBUG
,否则编译器无法围绕它进行优化。 这可以通过单独编译每个文件并合并它们来避免。 - 由于值是在文件开头定义的,因此无法灵活地事先接收值。
我已经考虑过从文件中删除所有var DEBUG
定义并在执行前将其注入源或外部定义的想法,但我遇到了两个问题:
- 在 extern 中定义它似乎没有任何作用。 未
- 编译代码中未定义的
DEBUG
会在浏览器中引发引用错误。
理想的选择是测试 window.DEBUG
,它不会抛出引用错误。 不幸的是,虽然注入/** @const */ var window = {}; /** @const */ window.DEBUG = false;
在顶层工作,但减少了if (window.DEBUG) {}
,如果放置在函数中,优化实际上会被恢复。
除非另一个编译器选项有效,否则唯一真正有意义的选项是使用 window.DEBUG
并在编译注入/** @const */ var DEBUG = false;
之前将 /'bwindow.DEBUG'b/
全局替换为 DEBUG
. 有没有更好的方法?
使用@define注释:
@define {boolean}
调试 = 真;
并使用选项进行编译
--define="DEBUG=false">
编译器的自定义版本将允许您执行此操作。 你基本上想要"内联常量变量":
options.setInlineConstantVars(true(;
您可以在此处添加它,在applySafeCompilationOptions中:http://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/javascript/jscomp/CompilationLevel.java?r=706
或者,您可以使用 Java API 并添加选项(无需修改编译器的代码(。Michael Bolin在这里举了一个如何做到这一点的例子:
http://blog.bolinfest.com/2009/11/calling-closure-compiler-from-java.html
这是一个古老的答案,但我找到了一种这里没有提到的方法。
(function(){
var DEBUG = true;
if (DEBUG) {
if (something === "wrong") {
console.warn("Stop! Hammer time!");
}
else if (something === "as expected") {
console.log("All good :-)");
}
}
foo();
})();
有了ADVANCED_OPTIMIZATIONS编译成这样:
"wrong" === something ?
console.warn("Stop! Hammer time!") :
"as expected" === something && console.log("All good :-)");
foo();
在我们的构建脚本中,我们可以重写 DEBUG 行以将其设置为 false
,然后会产生此输出。
foo();
发生这种情况的原因是关闭将删除无法访问的代码。 通过创建闭包并定义局部变量,Closure 可以看到我们不能做类似 window.DEBUG === true
的事情,因此可以保证代码永远不会运行。
您的DEBUG
变量当前是全局变量。GCC 不会在简单优化模式下删除或重命名全局变量,因此它们仍可用于其他脚本中可能想要访问它们的任何代码。尝试将代码封装到匿名函数中。
我解决"使用 SIMPLE_OPTIMIZATION 从闭包编译的 javascript 中删除调试函数"问题的方法是结合@John提出的类似方法以及使用一些 Nichols 更新@Brian。我只能通过放置这是我的主js文件的全局范围并进行自定义编译(使用多个.js文件仍然删除它们(来让编译器删除这些行
/** @const
* @type {boolean}
*/
var DEBUG = false;
//and used this format for my debug function
DEBUG && myLog('foo');
然后使用 ant 编译闭包编译器 java 以包含此选项 options.setInlineVariables(CompilerOptions.Reach.ALL(; 在编译级别.java文件中的应用安全编译选项功能下,如@john建议的那样。这对我有用,并没有像 ADVANCED 那样破坏我的代码库......
从代码中删除var DEBUG = true;
并将检查if (DEBUG)
的所有条件转换为if (goog.DEBUG)
。 修改编译器选项以读取--define goog.DEBUG=false
。 goog
变量内置于闭包库 API 中,为编译器提供选项和标志。
- 我可以从内部函数中产生吗?
- 从内部函数javascript内部分配外部函数的对象
- 将外部函数返回的id传递给内部函数
- 重复调用的同一函数会重置setTimeout内部函数
- Javascript中的内部函数作用域
- 对象内部函数内的对象文本的范围
- 内部函数不会为外部函数在 jQuery 中动态创建的元素赋值
- JavaScript 如何定义内部函数
- bluebird promise catch() 没有使用 Promise.CancelError 调用内部函数
- JavaScript 在内部函数中保留一个 var
- 如何使用Javascript访问内部函数
- 使用从内部函数返回的异步数据对外部函数返回promise
- Javascript对象看不到内部函数
- 为什么可以在内部函数成员中访问对象引用,而不能在内部属性成员中访问
- 如何将参数传递到内部函数中
- JavaScriptEs6在内部函数中引用了这一点
- 需要将内部函数绑定到元素的单击事件
- 将此对象传递给JavaScript中的内部函数
- JavaScript 面向对象的调用函数内部函数或调用函数 insede var
- 从内部函数内部突破while循环'的身体