イベント駆動プログラミングはGOTO文を使っている気分になる

@nqounetです。

昨日はイベント駆動版が手元になかったのでコールバック版でしたが、イベント駆動版も晒します。

とりあえずイベント駆動版のソース

ソースコードはこんな感じです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
(function($, global, undefined){
    'use strict';
    var lscache,
    Mustache,
    processing = {},
    generateCacheKey = function(path){
        return 'fetched:' + path;
    },
    fetchTemplate = function(path){
        console.debug('fetchTemplate');
        var key = generateCacheKey(path);
        $.get(path, function(template){
            console.debug('run $.get');
            lscache.set(key, template, 1);
            delete processing[key];
            $(global).triggerHandler(key); // fetch完了イベントを発行
        });
    },
    renderOnEvent = function(e){
        console.debug('renderOnEvent');
        var args = Array.prototype.slice.apply(e.data);
        render.apply(this, args);
    },
    render = function(path, args, cb){
        console.debug('render');
        var key = generateCacheKey(path);
        var template = lscache.get(key);
        if (template) {
            return cb(Mustache.render(template, args));
        }
        else {
            $(global).one(key, arguments, renderOnEvent);// fetch完了時のイベントを受信した時にもう一度実行する
            if (!processing[key]) {
                processing[key] = true;
                fetchTemplate(path);// keyになるfetchをしていない場合はfetchする
            }
        }
    },
    setVars = function(){
        // localize
        lscache = global.lscache || console.error('not ready `lscache.js`. hint : `bower install lscache`.');
        Mustache = global.Mustache || console.error('not ready `mustache.js`. hint : `bower install mustache`.');
    },
    init = function(){
        setVars();
        return {
            'render': render
        };
    };
    global.templates = init();
}(jQuery, this));

該当部分は日本語でコメントを書いていますが、この書き方が有用なのかについてはイマイチわかりません。

コールバックの嫌なところ

コールバックがあるとものすごく自由なんですよね。

で、その自由と引き換えに、メソッドの名前に非常に迷うことになります。

例えばfetchTemplateに対して、取得したテンプレートファイルでレンダリングするコールバックを渡すとrenderTemplateのように動作するわけです。

実際の仕事は、AJAXでgetするだけなのですが、その後のコールバックでレンダリングさせる、というふうに考えながらプログラミングしていると、名前に違和感を感じてしまうんですよ。

かと言って、renderTemplateという名前にするのは論外です。

猛者の方々はこの辺の気持ちをどう始末しているんでしょうか?

キャッシュがなければAJAXでテンプレートファイルを取得する

使い方としては、テンプレートファイルのURLと、テンプレートに反映させるオブジェクト、そしてコールバックです。

…結局コールバックは必要でした。

いや、今回のような場合なら、jQueryオブジェクトを渡せばコールバックがなくてもほどほどに使えますが、なんとなく微妙じゃないですかね?

1
2
3
4
5
// コールバックの場合
templates.render('templates/sns.mst', fbObj, function(content){ $this.append(content) });

// jQueryオブジェクトの場合は、引数の順序はこんな感じ?メソッド名も変えておかないとねぇ
templates.renderTo($this, 'templates/sns.mst', fbObj);

で、考え始めると、jQueryでメソッドチェーンできるようにすればいいんだよ、という感じになります。

1
$.templates('templates/sns.mst', fbObj).appendTo($this);

まあ、書けるかどうかも判断できませんが。

非同期のメソッドチェーン(=コールバック?)

この辺をうまく書こうとすると、jQuery.Deferredの世界へ足を踏み入れる必要があるんでしょうね。

「メソッドチェーンに見えて実はコールバック」だったら、非同期を意識しないでプログラミングできると思います。

というか、何故コールバックが必要かというと、非同期の処理が終わらないと次の処理ができないからです。

今までのプログラム(同期的プログラミング?)は、基本的には上から下、左から右という風に流れが決まっていました。

しかし、非同期の場合はそれが保証できないので、保証するための仕組みがコールバック、というふうに理解しています。

まあ、その部分は同期的に処理される、という事ですね。

queueはどう?

jQueryにはqueueというメソッドがあります。

そのイメージのとおり、jobを順番待ちさせる感じで使えるのですが、サンプルがアニメーションばかりなので、実際の使い所がよくわかりません。

ソースを見てみれば何かわかるのかもしれませんが、読み解ける自信がありません。

イベント駆動

イベント駆動というと、クリックした時、とか、マウスオーバーした時、のようにユーザーの操作によって動作するイメージですが、それだけではありません。

例えばコールバックの中に、動作が完了した、というイベントを発行すれば、そのイベントによって続きの動作が可能になります。

ただ、そればかりをやっているとGOTOを使っている気分になります。

非常に微妙です。

Hugo で構築されています。
テーマ StackJimmy によって設計されています。