Skip to content
uupaa edited this page May 23, 2016 · 48 revisions

Task は非同期プログラミングを簡単にします。
非同期処理をノードツリーのように階層化したり、親子関係を持たせる事ができます。 また非同期処理の待ち合わせを行う事ができます。

Namespace

Task is located in global.WebModule.Task. To invoke more easily, it can also be placed in global.Task.

Task の名前空間は global.WebModule.Task です。 より手軽に呼び出せるように、global.Task に配置することも可能です

API

  • new Task(taskName, taskCount, callback, tick) - 新しい Task インスタンスを生成します
    • flow state
      • Task#done(error) - 引数に応じてタスクの待機成功数または待機失敗数を+1します
      • Task#pass() - タスクの待機成功数を+1します
      • Task#miss() - タスクの待機失敗数を+1します
      • Task#exit() - タスクを強制的に終了します
    • accessor
      • Task#name:String - taskName を返します
      • Task#error:Error - タスクの失敗理由の設定と取得ができます
      • Task#state:String - タスクの待機状態を返します。
        戻り値は ""(in progress), "pass", "miss", "exit" のいずれかになります
      • Task#buffer:Array|Any - バッファの設定と取得ができます
      • Task#extend:UINT16 - タスクの待機数(taskCount)を追加します
      • Task#missable:UINT16 - タスクの待機失敗可能数を追加します
      • Task#finished:Boolean - 待機終了でtrueを返します
    • closure function
      • Task#donefn:Function - this を束縛済みの task.done 関数を返します
      • Task#passfn:Function - this を束縛済みの task.pass 関数を返します
      • Task#missfn:Function - this を束縛済みの task.miss 関数を返します
  • Task.dump():TaskSnapShotWeakSet - タスクのスナップショットを返します

new Task

new Task(taskName:String = "", taskCount:UINT16 = 1, callback:Function|Task = null, tick:Function = null) は合流ポイントを作成し Task#passtaskCount 回数以上呼ばれるまで待機します。

待機終了で callback を呼びます。Task#miss が1度呼ばれると待機失敗で callback を呼びます。

  • taskName にはユーザタスクを識別するための名前を指定します。デバッグで役立ちます
  • taskCount には待ち合わせるタスク数を 1 〜 65535 の範囲で指定します。0 は 1 とみなします
  • callback はタスク完了でコールバックする関数を指定します
    • callback(error:Error, buffer:Any):void の形でコールバックされる関数を指定します
      • error には待機成功で null が、待機失敗で Errorオブジェクトが格納されています
      • buffer には Task#buffer が渡されます
  • tick(task:Task):void は状態が変化する直前のタイミングでコールバックする関数です
    • tick(task:Task):void の形でコールバックされる関数を指定します
    • 状態の更新は Task#pass, Task#miss, Task#done の直後に発生します

Task.prototype.pass

Task#pass():void は待機成功数を +1 します。待機成功数が taskCount 以上になると待機成功で終了し callback(null, task.buffer):void を実行します。

var task = new Task("Task#pass", 1, function(error, buffer) { // error = null, buffer = []
});

task.pass(); // 待機成功で終了

Task.prototype.miss

Task#miss():void は待機失敗数を +1 します。待機失敗可能数が missable 以上になると待機失敗で終了し callback(task.error, task.buffer):void を実行します。

var task = new Task("Task#miss", 1, function(error, buffer) { // error = new Error("miss"), buffer = []
});

task.miss(); // 待機失敗で終了

Task.prototype.exit

Task#exit():void は待機失敗で終了し callback(task.error, task.buffer) を実行します。

このメソッドは待機失敗可能数 missable の値を無視して、待機を強制終了させる事ができます。

var task = new Task("too many tasks", 100, function(error, buffer) {
        console.log(error.message); // "exit"
    });

task.missable = 100; // 100回失敗するまで耐える
task.exit();         // 強制終了 -> callback(new Error("exit"), task.buffer)

Task.prototype.done

Task#done(error:Error|null):void は、error の値に応じて task.pass() か task.miss() として機能します。

  • error が Error オブジェクト以外なら、task.pass() として機能します。
  • error が Error オブジェクトなら task.error = error; task.miss() として機能します

エラーハンドリングを行うコードは task.done を使う事でスッキリと記述できます。

// if (error) {
//     task.error = error;
//     task.miss();
// } else {
//     task.pass();
// }

task.done(error);

Task.prototype.name

Task#name:String は taskName を返します。read-onlyです。

var task = new Task("Task#name");

console.log(task.name); // "Task#name";

Task.prototype.error

Task#error:Error = Error|String|null は 失敗理由を設定します。 error のデフォルト値は null です。

文字列はエラーオブジェクトに変換してから設定します。

var task = new Task("Task#error", 1, function(error) {
        console.log(error.message); // "error-reason"
    });

task.error = new Error("error-reason");
task.error = "error-reason"; // こちらも同じ結果になります。

console.log( taks.error.message ); // "error-reason"

task.miss(); // 待機失敗で終了

Task.prototype.state

Task#state:String は、待機状態を返します。デフォルト値は "" です。
state は "", "pass", "miss", "exit" の何れかになります。

Task#state Task#finished 状態
"" false 待機中(in progress)
"pass" true 待機成功で終了
"miss" true 待機失敗で終了
"exit" true 待機失敗で終了
var task1 = new Task();
var task2 = new Task();
var task3 = new Task();
var task4 = new Task();

task2.pass();
task3.miss();
task4.exit();

console.log( task1.state ); // ""
console.log( task2.state ); // "pass"
console.log( task3.state ); // "miss"
console.log( task4.state ); // "exit"

Task.prototype.finished

Task#finished:Boolean は待機終了状態で true を返します。task.state も参照してください。

var task = new Task();

task.pass();

console.log( task.finished ); // true;

Task.prototype.buffer

Task#buffer:Any は、バッファの設定と取得を行います。デフォルト値は空の配列([])です。

以下は、task.buffer の配列に要素を格納し、callback の引数から task.buffer の要素を取得しているコードです。
待機終了からしばらくすると task.buffer の内容は解放(GC)されます。

var task = new Task("", 1, function(error, buffer) {
    console.log(buffer.join()); // "1,2,3"
});

task.buffer.push(1, 2, 3);
task.pass();

// 待機終了後しばらくすると task.buffer の内容は初期化されます
setTimeout(function() {
    console.log( task.buffer.length ); // -> 0
}, 1000);

Junction で各タスクを連結している場合は、連結している Task と buffer を共有した状態になります。

SharedBuffer も参照してください。

Task.prototype.extend

Task#extend:UINT16 は、現在の taskCount の値(待機数)に、引数で指定された値を追加します。

var task = new Task("Task#extend", 1);

task.extend = 2; // taskCount は 3 になります。3 = 1 + 2

task.pass();
task.pass();
task.pass(); // 待機終了

task.extend は、次々にタスクが追加されるケースで有用です。

Task.prototype.missable

Task#missable:UINT16 は、現在の missable の値(待機失敗可能数)に引数で与えられた値を追加します。missable のデフォルト値は0です。

missable が 0 の状態では task.miss が1度呼ばれると、待機失敗で終了します。

var task = new Task("Task#missable", 1, function(error, buffer) {
        if (error) {
            console.log("待機失敗");
        } else {
            console.log("待機成功");
        }
    });

task.missable = 1; // missable は 1 になります。 1 = 0 + 1

task.miss(); // missable が 1 なので、1度目の失敗は許容されます
task.pass(); // 待機成功で終了します

Task#missable を使うと ある程度は失敗する可能性のある 処理を簡単に記述できます。

// 画像をCDN1からダウンロードできない場合は、CDN2からダウンロードする
var task = new Task("image download from CDN", 1, function(error, buffer) {
    console.log("done");
});
task.missable = 1; // 失敗を1度まで許容する

_download(["//cdn1.example.com/images/a.png",
           "//cdn2.example.com/images/a.png"], 0, task);

function _download(url, cursor, task) {
    // call fetch(url, callback, errorCallback):void function
    fetch(url[cursor], function(res) {
        task.buffer.push(res);
        task.pass();
    }, function(error) {
        task.miss();
        if (!task.finished) {
            _download(url, cursor + 1, task);
        }
    });
}

Task.prototype.donefn

Task#donefn:Function は this を束縛した done 関数を返します。donefn の返す関数を呼ぶと task.done() が実行されます。

var task = new Task("Task#donefn");

var donefn = task.donefn; // var fn = task.done.bind(task); と等価です

setTimeout(donefn, 1000); // 1秒後に task.done() が実行され、待機成功で終了します

Task.prototype.passfn

Task#passfn:Function は this を束縛した pass 関数を返します。passfn の返す関数を呼ぶと task.pass() が実行されます。

var task = new Task("Task#passfn");

foo( task.passfn, task.missfn );

function foo(passfn, missfn) {
    passfn(); // 待機成功で終了します
}

Task.prototype.missfn

Task#missfn:Function は this を束縛した miss 関数を返します。missfn の返す関数を呼ぶと task.miss() が実行されます。

var task = new Task("Task#missfn");

foo( task.passfn, task.missfn );

function foo(passfn, missfn) {
    missfn(); // 待機失敗で終了します
}

Task.dump

Task.dump():TaskSnapShotWeakSet は、現在待機状態にある Task のインスタンスの一覧(スナップショット)を返します。 この関数を使うと、タスクの状態を調べる事ができます。

  • この関数はデバッグ用です
  • 終了しない(実行したままになっている)タスクを調査することができます
  • 戻り値は WeakSet です。不要になると自動的に GC されます
var task1 = new Task("in progress task 1");
var task2 = new Task("in progress task 2");

// この時点で Task.dump() を行うと 2つの task が登録されている事がわかります
console.log( Task.dump() ); // { task1, task2 }


task1.pass();

// しばらく(恐らく10秒ほど)まってから、もういちど Task.dump() を行うと、
// task1 は GC され、消えているでしょう
setTimeout(function() {
    console.log( Task.dump() ); // { task2 }
}, 10 * 1000);