FOT.task(関数の実行) - fairy.ouchi.to


ソース


警告

この取説は現状の FOT.task の仕様に基づくものです。
今後 FOT.task の仕様が変更される可能性があります。


概要

引数で渡した関数を setTimeout で実行します。


基本的な使い方


// task.jsを読み込んで、FOT.task() を使えるようにしておきます。
// ※ 変数 FOT 以外の名前空間への汚染はありません。

function xxx_a(){ }
function xxx_b(){ }

// setTimeout(xxx_a, 300) を実行し、xxx_a() の終了後に setTimeout(xxx_b, 200) を実行
FOT.task([
    { exec : xxx_a, wait : 300 },
    { exec : xxx_b, wait : 200 },
]);

関数一覧

基本関数
FOT.task
単体関数実行
FOT.task.exec
FOT.task.ready
FOT.task.loop
FOT.task.while

全ての機能は FOT.task で実行可能です。
他の関数は引数の形式が違うだけの構文糖です。


基本関数

FOT.task

引数で指定した関数を順番に setTimeout で実行します。

FOT.task( array execute_list );

execute_list:実行する関数を含むオブジェクトの配列。

引数の配列の各要素は exec、wait、cnt を持つオブジェクトです。
execute_list[0] = { exec : function execute [, wait : number wait = 0 ] [, cnt : number cnt = 1 ] };

execute
実行する関数。
省略不可。
wait
0以上の整数、または -1
0以上の場合は setTimeout に渡すミリ秒。
-1の場合は実行タイミングを document.readyState で判断する。
省略した場合は 0 。
cnt
1以上の整数、または -1
1以上の場合は関数の実行回数。
-1 の場合は次に実行する関数を戻り値で判断する。
省略した場合は1回実行する。

wait に -1 を指定した場合、その関数の setTimeout を実行するタイミングで document.readyState == "loading" であれば、実行せずに待機します。 その後、document.readyState が "interactive" 以降になったタイミングで setTimeout を実行します。
実行するタイミングで既に "interactive" 以降だった場合、wait : 0 として実行します。

cnt に 1 以上を指定した場合、その関数を指定回数だけ setTimeout で繰り返し実行します。
cnt に -1 を指定した場合、その関数の戻り値が真の場合は、次もその関数を setTimeout で実行します。 戻り値が偽の場合は、次に指定されていた関数を setTimeout で実行します。
注意:0 を指定しても0回実行にはなりません。省略した場合と同じく、1回実行になります。


単体関数実行

FOT.task.exec

FOT.task.exec( function execute [, number wait = 0 ] );

関数を setTimeout で1回実行します。
FOT.task([{ exec : execute, wait : wait }]) と同じです。

FOT.task.ready

FOT.task.ready( function execute );

関数を setTimeout で1回実行します。document.readyState == "loading" であれば、変わるまで待機したあと実行します。
FOT.task([{ exec : execute, wait : -1 }]) と同じです。

FOT.task.loop

FOT.task.loop( function execute, number cnt [, number wait = 0 ] );

関数を setTimeout で cnt 回実行します。
FOT.task([{ exec : execute, wait : wait, cnt : cnt }]) と同じです。

FOT.task.while

FOT.task.while( function execute [, number wait = 0 ] );

関数の戻り値が真である限り、関数を setTimeout で繰り返し実行します。
FOT.task([{ exec : execute, wait : wait, cnt : -1 }]) と同じです。


仕様や設計方針などについてのあれこれ

このライブラリを使用する際に留意しておくべき事柄など。


引数の検査

一切やっていません。このマニュアルに明記されている以外の引数を渡せば、エラーが発生したり、想定外の動作をすることになります。
たとえば exec を省略したり関数以外を渡せばエラーになりますし、cnt に整数以外を渡せば無限ループします。

止まってはいけないプログラムで利用するのであれば、自分で try-catch するなり、引数と戻り値を完全にチェックするなりしてください。
最も適切な対応として、大切なプログラムでは、このライブラリを利用しないことをオススメします。


ソース

何やってるか知りたい人なら、見れば分かる程度には単純なはずです。

やってることはただのマトリョーシカ。「引数の関数を実行した後に次の関数を setTimeout に投げる」関数を作って、 それを順番に入れ子にしていって、一番最初の関数を setTimeout に投げる。それだけ。


何で作ったの?

元々の作成理由は document.readyState を待つ処理の定型化です。


FOT.task([
    { exec : initVariables }, // 前処理1
    { exec : createNode }, // 前処理2
    { exec : appStart, wait : -1 }, // 実行開始
]);

最初の関数を setTimeout で実行し、終了後すぐに次の関数を setTimeout で実行して、 2つ目の関数が終了した時点で document.readyState が "loading" であれば、 変わるのを待ってから3つ目を setTimeout で実行します。
実行順の保証と document.readyState の監視が目的だったので、setTimeout に渡すミリ秒の引数は単なるついで。

前の2つを分割することにあまり意味はありませんが、 一応、setTimeout に投げておいていったん処理を終了することで、 ブラウザが処理を受け付けるタイミングができるという効果があります。
銀行のATM行列と同じで、1つのプログラムが複数の処理を連続して実行すると、いつまでも占有が続きますが、 このように処理を切ることで、いわば処理ごとにATM行列に並び直すような状態になります。 ブラウザはこのタイミングで画面の描画やマウス・キーボードの入力を受け付けることができるので、 1つのプログラムが占有を続けてしまっていることで画面がロックしたままという状況を避けられます。

で、このライブラリを作ったことで長時間の処理によるロックの回避を覚えたので、 万年カレンダーではそれを利用しています。


function createCalendar()
{
    let div = itf_view.cal;
    div.fotSetEvent("click", elClickCalendar);
    let time = state.time.clone();
    let ce_cnt = calc_gc_month();
    let clip = FOT.elm.createClip();
    let count = 0;

    let start = Date.now();
    state.now = start;

    if (loop())
    {
        FOT.task.while(loop);
    }

    function loop()
    {
        if (state.now != start){ return; }

        clip.push("hr");
        for (let m = 1; m <= 12; m++){ clip.push(createCalTable(time, (ce_cnt++) ? null : {})); }
        div.push(clip);
        itf_view.loop_year.textContent = ++count;

        if (count < state.loop){ return true; }

        div.push("hr");
        itf_view.exec_time.textContent = " ( " + ((Date.now() - start) / 1000) + " 秒)";
    }
}

関数 loop() はカレンダー1年分(12か月)の表示です。最初の1年だけは即時実行して、2年目からは FOT.task.while で回しています。 年数分のループが終わるまで true を返して、最後の実行時に終了処理をして戻り値なしで終わります。
実行時点でループ回数が決定しているので FOT.task.while ではなく FOT.task.loop でもいいんですが、 処理中に次のカレンダー表示が始まった場合に中断できるようにしています(関数 loop() の1行目)。

FOT.task に渡す関数は引数を設定できませんが、この例を見て分かる通り、 関数ごと取り込んで外の変数を見ればいいので問題にはならないはずです。 これが問題になるような大規模なプログラムでの利用を想定してません:-)

実際のところ、そこらのライブラリで同じ機能ぐらいあるだろーとは思ってますがw
自分が作ったオモチャ(プログラム)なら、 自分でいくらでもいじり倒せるので、今後もいじり続けるつもりです。