9

クロージャにテスト フックを追加できるように、関数からデバッグ コードを削除する方法を探しています。Google Closure Compiler advanced: remove code blocks at compile timeを読ん で、次のようにデバッグ コードの削除をテストしました。

/** @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 の回答に従って、私は独自のコンパイラを実装しましたが、次の構成がif (DEBUG) {}a の場合にコードの内側と外側から削除されることがわかりました@define

CompilerOptions options = new CompilerOptions();
CompilationLevel.SIMPLE_OPTIMIZATIONS.setOptionsForCompilationLevel(options);
//options.setInlineConstantVars(true);
options.setInlineVariables(CompilerOptions.Reach.ALL);
options.setDefineToBooleanLiteral("DEBUG", false);

これは、次の制限がある 1 つのファイルに対しては十分に機能します。

  1. これはvar DEBUG各ファイルで定義する必要がありますが、これは悪い習慣です。
  2. 複数のファイルを結合する場合、単一のファイルしか持つことがvar DEBUGできないか、コンパイラがその周りを最適化できません。これは、各ファイルを個別にコンパイルしてマージすることで回避できます。
  3. 値はファイルの先頭で定義されているため、事前に値を受け取る柔軟性はありません。

var DEBUGファイルからすべての定義を削除し、実行前にソースまたは extern に挿入するというアイデアをいじりましたが、次の 2 つの問題に遭遇しました。

  • extern で定義しても何もしないように見えます。
  • コンパイルされていないコードでundefinedDEBUGを指定すると、ブラウザで参照エラーがスローされます。

理想的なオプションはwindow.DEBUG、参照エラーをスローしない test です。残念ながら、注入/** @const */ var window = {}; /** @const */ window.DEBUG = false;はトップレベルで機能し、 を減らしますif (window.DEBUG) {}が、関数に配置すると、最適化は実際には元に戻ります。

別のコンパイラ オプションが機能しない限り、本当に意味のある唯一のオプションは、window.DEBUGコンパイル前に injectを使用し、 with を/** @const */ var DEBUG = false;グローバルに置換することです。より良い方法はありますか?/\bwindow.DEBUG\b/DEBUG

4

6 に答える 6

3

コンパイラのカスタム ビルドを使用すると、これを行うことができます。基本的に「定数変数をインライン化」したい:

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

于 2012-07-09T23:33:35.243 に答える
2

これは古い答えですが、ここで言及されていない方法を見つけました。

(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ため、コードが実行されないことが保証されます。

于 2013-08-30T11:18:03.907 に答える
1

あなたのDEBUG変数は現在グローバルです。GCC は、単純な最適化モードではグローバル変数を削除したり名前を変更したりしないため、それらにアクセスする可能性のある他のスクリプトのコードで引き続き使用できます。コードを匿名関数に囲んでみてください。

于 2012-07-09T22:59:40.880 に答える
1

「SIMPLE_OPTIMIZATIONを使用してクロージャーコンパイルされたjavascriptからデバッグ機能を削除する」という問題を解決した方法は、@Johnが提案するのと同様の方法を組み合わせ、@Brian Nicholsの更新を使用することでした。これをメインの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); @johnが示唆するように、CompilationLevel.javaファイルのapplySafeCompilationOptions関数の下。これは私にとってはうまくいき、ADVANCEDのようにコードベースを壊しませんでした...

于 2013-10-12T02:10:52.520 に答える
0

コードから削除var DEBUG = true;し、チェックするすべての条件を に変換しif (DEBUG)ますif (goog.DEBUG)。コンパイラ オプションを read に変更します--define goog.DEBUG=false。このgoog変数は、Closure Library API に組み込まれており、コンパイラにオプションとフラグを提供します。

于 2012-07-09T20:45:07.893 に答える