latest log

酩酊状態で書いたエンジニアポエムです。酩酊状態で読んでください。

mofmof.js の Future でシンプルに非同期処理を記述する

以下は、画像を3つ読み込み全て読み込み後に canvas でまとめて描画するコードです。

http://mofmof-js.googlecode.com/svn/trunk/test/base.js.htm に行き、コンソールに以下のコードを貼り付けると動作します。

(function() {
    var images = [
            "http://www.google.co.jp/images/nav_logo102.png",
            "http://k.yimg.jp/images/top/sp/logo.gif",
            "http://www.bing.com/fd/s/a/sw3.png"
        ];

    var canvas = document.createElement("canvas");

    canvas.width  = 800;
    canvas.height = 800;

    document.body.appendChild(canvas);

    var ctx = canvas.getContext("2d");


    // 3個の画像全てを読み込み終わったら drawCanvas を呼びます
    var future = drawCanvas.every(images.length);

    images.each(function(url, index) {

        // mm.Class.Image に future を bind すると
        // 画像の読み込み完了/失敗のたびに
        // future.pass(node) や future.miss(node) を呼びます

        new mm.Class.Image(url, future, index);
    });

    function drawCanvas(result) { // { ok: Boolean,
                                  //   args: NodeArray,
                                  //   state: Number }
        if (result.ok) { // ok = 完了
            result.args.each(function(node) {
                ctx.drawImage(node, node.index * 200,  // sx
                                    node.index * 200); // sy
            });
        }
    }
})();

全ての画像の読み込みを待たず、読み込みが終わったものから canvas で次々描画するには以下のようにします。

(function() {
    var images = [
            "http://www.google.co.jp/images/nav_logo102.png",
            "http://k.yimg.jp/images/top/sp/logo.gif",
            "http://www.bing.com/fd/s/a/sw3.png"
        ];

    var canvas = document.createElement("canvas");

    canvas.width  = 800;
    canvas.height = 800;

    document.body.appendChild(canvas);

    var ctx = canvas.getContext("2d");

    // 3個の画像全てを読み込み終わったら drawCanvas を呼びます
//  var future = drawCanvas.every(images.length);

    // 画像を1つ読み込む毎に drawCanvas を呼びます。これを3回くり返します
    // 全て読み込み終了で mm.nop (何もしない関数) を呼びます
    var future = mm.nop.every(images.length, drawCanvas);

    images.each(function(url, index) {

        // mm.Class.Image に future を bind すると
        // 画像の読み込み完了/失敗のたびに
        // future.pass(node) や future.miss(node) を呼びます

        new mm.Class.Image(url, future, index);
    });

    function drawCanvas(result) { // { ok: Boolean,
                                  //   args: NodeArray,
                                  //   state: Number }
//      if (result.ok) { // ok = 完了
//          result.args.each(function(node) {
//              ctx.drawImage(node, node.index * 200,  // sx
//                                  node.index * 200); // sy
//          });
//      }
        // 100(継続中) または 200(読み込み完了) で描画します
        if (result.state < 400) {

            // 最後のimg要素(読み込みが終わったimg要素)を参照します
            var node = result.args.tail();

            ctx.drawImage(node, node.index * 200,  // sx
                                node.index * 200); // sy
        }
    }
})();

このように、Future と連携する機能をもった mm.Class.Image を使うことで本来のロジックに注力できます。