非同期マクロ同時の順番を制御しやすくすNo.10696
こみやんま さん 25/04/28 01:15
 
非同期マクロ同時の順番を制御しやすくする機能を提案します。

■ 非同期のスクリプトは主に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, {timeou
t:10000});
}





■ 実装したとしたらの挙動

上で出現している、2つの未実装の
@ hidemaru.setJsCompleteNotify
A hidemaru.waitJsCompleteNotify
の2つの関数は、
現段階でも以下のように仮組みすれば、どういった挙動になるのか確認できます。

// Aのマクロの先頭にこれを貼り付け
hidemaru.setJsCompleteNotify = function(label, notifyName) {
    setstaticvariable(label, notifyName, 2);
}

// Bのマクロの先頭にこれを貼り付け
hidemaru.waitJsCompleteNotify = function(label, notifyName, onEndCallbackFun
ction, 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(tickHandle
r); }, option.timeout );
    }
}

[ ]