|
非同期マクロ同時の順番を制御しやすくする機能を提案します。
■ 非同期のスクリプトは主に2系統
@ 常時実行している。
1時間でも2時間でも、該当のファイルがオープンしている限り、
裏でずっと動いているもの
A 数秒など、短時間だが時間がかかるので非同期にまわしているか、
あるいは非同期要素があるので、非同期になっている。
・テキスト数十万行などが対象で、完了に数秒かかる
・ネットワークAPIを利用しているため、返答に0.5〜3秒ほどかかる
ネットワークサービスはほとんどが rest api ですが、
原則 jsmode の fetch を使ってアクセスするでしょうから、
(同期でやったら明らかに秀丸が硬直するのでw)
Promiseで書こうが、await で書こうが必然的に非同期になるでしょう。
問題はAの非同期のマクロの(あくまでも概念的な)終了をいかにして待つのがスマートなのか?
ということです。
■ awaitjs は筋が悪い
すでに秀丸に実装されている「awaitjs」は、
「同期」待機(「マクロ実行中」というステータスでの待機)となるため、
正直「仕様がすごく悪い」といえます。
(以前もこのことを強く講義しましたw)
同期待機であるため、非常にデッドロックしやすく、かつ、
全ての秀丸を巻き込みやすいです。
同期待機してるものだから、待機の間、「新たなマクロ実行」も「postExec」も効かなくなり、
javascriptの処理に「ほんの僅かな綻び」があるだけで、
あっけなくデッドロックし、詰みやすい
■ 非同期のものは、非同期として待機し、条件を満たしたら呼び出してもらうのが良い形
そうではなく、JavaScriptらしく、
あくまでも非同期の中で非同期として待機します。
以下の形を提案します。
「待機」をしていても、
・「新たなマクロ実行」も
・「他の非同期処理実行」も、
両方の邪魔をしない形です。
// マクロA
jsmode "JScript\\" + "func1_" + currentmacrofilename;
js {
debuginfo(2);
// 非同期であるものの「終了の概念」があるマクロなのであれば、その気付き情報を先頭(付近で)クリアする。
hidemaru.setJsCompleteNotify("HmTestMacro1", "");
function func1() {
console.log("func1");
// そして、その処理が完了したら(あくまでも、その作者にとっての概念的な終了だけど)、その情報を気付きとして登録する。
hidemaru.setJsCompleteNotify("HmTestMacro1", "end");
}
hidemaru.setTimeout(func1, 3000);
}
// マクロB
// ファイル2がマクロAに続けて execmacro などされてるとする。
// マクロAの(概念的な)終了を待って、直後に(実質的な)実行を行いたいとする。
jsmode "JScript\\" + "func2_" + currentmacrofilename;
js {
debuginfo(2);
function mainAsync() {
console.log("待ってたよ");
}
// マクロAの(非同期の)、とある気付き情報を、非同期のまま(他の邪魔をせず)待機する。
// ただし、最大で10秒(10000ミリ秒)まで。
hidemaru.waitJsCompleteNotify("HmTestMacro1", "end", mainAsync, {timeout:10000});
}
■ 実装したとしたらの挙動
上で出現している、2つの未実装の
@ hidemaru.setJsCompleteNotify
A hidemaru.waitJsCompleteNotify
の2つの関数は、
現段階でも以下のように仮組みすれば、どういった挙動になるのか確認できます。
// Aのマクロの先頭にこれを貼り付け
hidemaru.setJsCompleteNotify = function(label, notifyName) {
setstaticvariable(label, notifyName, 2);
}
// Bのマクロの先頭にこれを貼り付け
hidemaru.waitJsCompleteNotify = function(label, notifyName, onEndCallbackFunction, option) {
var tickHandler = null;
function tick() {
var currentStatus = getstaticvariable(label, 2);
if (currentStatus == notifyName) {
hidemaru.clearTimeout(tickHandler);
if (typeof(onEndCallbackFunction) == "function") {
onEndCallbackFunction();
}
}
else {
tickHandler = hidemaru.setTimeout(tick, 100);
}
}
tickHandler = hidemaru.setTimeout(tick, 0);
// タイムアウトしてる
if (option && option.timeout) {
hidemaru.setTimeout( function() { hidemaru.clearTimeout(tickHandler); }, option.timeout );
}
}
|
|