Atomプラグイン plantuml-viewer で大きなUMLを扱った場合の問題と対処法
以前に紹介したAtomプラグインのplantuml-viewerについて。使っていて少々気になる点がありました。
概ね問題なく快適に使えているのですが、変換するUMLのサイズが大きくなってくると
極端にレスポンスが悪くなったり、最後の入力結果が反映されなかったりすることがあります。
plantumlによる変換処理は、子プロセスに投げられてバックグラウンドで処理されるのですが、この部分の処理が以下の様になっているために、前述の問題が起きると考えられます。
- 1文字入力する度に変換処理が走る(その結果、同時に実行されるプロセスが多くなる)
- 結果が表示されるのは、処理の実行順ではなく完了した順番
シーケンス図で表すとこんな感じでしょうか
実際問題、プレビューを画像をここまで頻繁に更新する必要はないと思うので、「一定時間入力が無かったら更新する」といった、所謂 Throttle の動作にした方が良いのでは。。。 などと考えていたら、Githubにそのものズバリのプルリクエストが上がっていました。
[throttle image updates by KylePDavis · Pull Request #10 · markushedvall/plantuml-viewer · GitHub
これはグッジョブ!と、マージされるのを待っていたのですが一向にマージされる気配が無いので、ひとまず自分の環境だけにでも取り込んでしまいましょう!
plantuml-viewer の画像更新をThrottleにする
修正方法は、プルリクエストの内容を参照して頂く方が早いとは思いますが、ここでもざっくりと説明しておきます。
- 修正するファイルは1つのみで、以下のパスにあります。
%USERPROFILE%\.atom\packages\plantuml-viewer\lib\plantuml-viewer-view.js
- このファイルの PlantumlViewerView クラス内に、
setTimeout()
関数を使用して更新頻度を調整するqueueUpdate()
関数を追加します。
function PlantumlViewerView (editor) { //...(略)... var updateImageTimerId = 0 function queueUpdate () { if (updateImageTimerId) return updateImageTimerId = setTimeout(function () { updateImage() updateImageTimerId = 0 }, 20) } }
- setTimeout()の第2引数に、待機時間を指定します。待機時間の間入力が無かった場合に更新処理(
updateImage()
)が実行されます。プルリクエストのコードでは20ミリ秒となっていますが、少し短すぎるような気もします。この辺は実際に動かしながら調節すると良いでしょう。 - 後は、既存のコードにある 画像更新処理関数
updateImage()
を作成したqueueUpdate()
関数に置き換えるだけです。
// ファイル内のすべてのupdateImage()をqueueUpdate()に置き換える //...(略)... function attached () { disposables = new CompositeDisposable() //updateImage() 置き換え queueUpdate() if (atom.config.get('plantuml-viewer.liveUpdate')) { disposables.add(editor.getBuffer().onDidChange(function () { if (loading) { waitingToLoad = true return } //updateImage() 置き換え queueUpdate() })) interval = setInterval(function () { if (panZoom) { if (width !== self.width() || height !== self.height()) { //updateImage() 置き換え queueUpdate() width = self.width() height = self.height() } } }, 500) } //...(略)...
これで、より快適なplantumlライフが送れるようになりました!