提高 Rhino CLI 實用程序的性能
當我在 Yahoo! 工作時,我們花了很多時間來改進我們的構建和簽入系統。其中一部分意味著使用 JSLint 進行 JavaScript 驗證和我為 CSS 驗證編寫的工具(與 CSS Lint 無關)。這兩個工具都是使用基於 Java 的命令行 JavaScript 引擎 Rhino 運行的。我們開始使用這些工具並很快發現它們非常有用……當它們實際運行時。開發人員似乎很難記住運行 lint 檢查。
這不一定是開發人員的錯。實際上,可以根據正在完成的工作類型運行許多 lint 檢查。我們很快決定將所有檢查合併到一個步驟中,以便每個人每次都運行相同的檢查。就在那時我們發現了一個問題:在我們龐大的代碼庫上完成這一步需要幾分鐘。不太利於生產力。
經過一番挖掘,我們發現問題的根源在於基於 Rhino 的實用程序。雖然我們對 JavaScript 進行了修補並得到了一些改進,但它還遠遠不夠好。我們在以一種非常簡單的方式更改實用程序時發現的最大變化:允許它們處理多個文件。
要了解更改,請考慮您當前如何使用 Rhino 運行 JSHint:
java -jar js.jar jshint-rhino.js yourfile.js
這將使用 Rhino 執行 jshint-rhino.js 文件,並將 yourfile.js 作為要運行的文件傳入。大多數使用 JSHint 的構建系統基本上對每個文件運行一次同一行 .例如,這是我在 CSS Lint 構建腳本中使用的 Ant 目標:
<target name="lint">
<apply executable="java" parallel="false" failonerror="true">
<fileset dir="${src.dir}" includes="**/*.js" />
<arg line="-jar"/>
<arg path="${lib.dir}/js.jar"/>
<arg path="${lib.dir}/jshint.js" />
<srcfile/>
<arg line="curly=true,forin=true,latedef=true,noempty=true,undef=true,rhino=false"/>
</apply>
</target>
運行這個目標將導致每個文件都通過 JSHint 運行。因此,例如,如果只有五個文件,這是等價的:
java -jar js.jar jshint-rhino.js yourfile1.js
java -jar js.jar jshint-rhino.js yourfile2.js
java -jar js.jar jshint-rhino.js yourfile3.js
java -jar js.jar jshint-rhino.js yourfile4.js
java -jar js.jar jshint-rhino.js yourfile5.js
這沒什麼錯,真的。目標運行整個 CSS Lint 代碼庫大約需要 45 秒。從總體上看,這還不錯,但是當您想經常進行檢查時,這會很痛苦。你能發現問題嗎?
考慮一下:儘管 Rhino 沒有 Node.js 快,但它仍然非常快。那麼你認為大部分時間都花在了哪裡呢?
問題在於為每個文件設置和拆除 JVM。這是你每次運行 Java 時都要支付的固定成本,如果你的代碼庫中有幾十個文件,那麼你要支付幾十倍的成本。你真正想做的是相當於:
java -jar js.jar jshint-rhino.js yourfile1.js yourfile2.js yourfile3.js yourfile4.js yourfile5.js
使用單個 JVM 通過 JSHint 運行所有 JavaScript 比單獨運行每個文件要快得多。不幸的是,JSHint Rhino CLI 不支持傳入多個文件,因此作為我工作的一部分,我進行了更改並提交了一個拉取請求。該更改現已合併到 JSHint。
一旦 JSHint 能夠一次評估多個文件,我將 Ant 目標更改為以下(感謝 CSS Lint 郵件列表中的 Tim Beadle):
<target name="lint">
<fileset dir="${src.dir}" includes="**/*.js" id="jsfiles.raw"/>
<pathconvert pathsep=" " property="jsfiles.clean" refid="jsfiles.raw" />
<exec executable="java">
<arg line="-jar"/>
<arg path="${lib.dir}/js.jar"/>
<arg path="${lib.dir}/jshint.js" />
<arg line="${jsfiles.clean} curly=true,forin=true,latedef=true,noempty=true,undef=true,rhino=false" />
</exec>
</target>
現在,運行 ant lint
在 CSS Lint 代碼庫上需要 3 秒 .那是 3 秒,低於更改前的 45 秒。還不錯。
Rhino 和 Node.js 的 CSS Lint CLI 已經支持在命令行中傳入多個文件,因此您可以利用相同的模式快速驗證所有文件。
這裡的底線是密切關注您的 Rhino CLI。創建和銷毀 JVM 的開銷是您在代碼上使用實用程序時不應該多次受到懲罰的事情。如果您使用任何基於 Rhino 的 JavaScript 實用程序,請要求作者支持傳入多個文件。如果該實用程序已經可以接受多個文件,那麼請確保您的構建腳本實際上是一次傳入多個文件。